Introduce Mini-Apps (#3868)

This commit is contained in:
Alexander Zinchuk 2023-09-25 13:00:13 +02:00
parent 548430bd2e
commit acc962bcf5
25 changed files with 560 additions and 337 deletions

View File

@ -118,6 +118,11 @@ interface Navigator {
setAppBadge?(count: number): Promise<void>; setAppBadge?(count: number): Promise<void>;
} }
type Undefined<T> = {
[K in keyof T]: undefined;
};
type OptionalCombine<A, B> = (A & B) | (A & Undefined<B>);
// Fix to make Boolean() work as !! // Fix to make Boolean() work as !!
// https://github.com/microsoft/TypeScript/issues/16655 // https://github.com/microsoft/TypeScript/issues/16655
type Falsy = false | 0 | '' | null | undefined; type Falsy = false | 0 | '' | null | undefined;

View File

@ -75,8 +75,12 @@ export function buildApiAttachBot(bot: GramJs.AttachMenuBot): ApiAttachBot {
hasSettings: bot.hasSettings, hasSettings: bot.hasSettings,
shouldRequestWriteAccess: bot.requestWriteAccess, shouldRequestWriteAccess: bot.requestWriteAccess,
shortName: bot.shortName, shortName: bot.shortName,
peerTypes: bot.peerTypes.map(buildApiAttachMenuPeerType), isForAttachMenu: bot.showInAttachMenu!,
isForSideMenu: bot.showInSideMenu,
attachMenuPeerTypes: bot.peerTypes?.map(buildApiAttachMenuPeerType)!,
icons: bot.icons.map(buildApiAttachMenuIcon).filter(Boolean), icons: bot.icons.map(buildApiAttachMenuIcon).filter(Boolean),
isInactive: bot.inactive,
isDisclaimerNeeded: bot.sideMenuDisclaimerNeeded,
}; };
} }

View File

@ -214,17 +214,28 @@ export async function requestWebView({
} }
export async function requestSimpleWebView({ export async function requestSimpleWebView({
bot, url, theme, bot,
url,
theme,
startParam,
isFromSwitchWebView,
isFromSideMenu,
}: { }: {
bot: ApiUser; bot: ApiUser;
url: string; url?: string;
theme?: ApiThemeParameters; theme?: ApiThemeParameters;
startParam?: string;
isFromSwitchWebView?: boolean;
isFromSideMenu?: boolean;
}) { }) {
const result = await invokeRequest(new GramJs.messages.RequestSimpleWebView({ const result = await invokeRequest(new GramJs.messages.RequestSimpleWebView({
url, url,
bot: buildInputPeer(bot.id, bot.accessHash), bot: buildInputPeer(bot.id, bot.accessHash),
themeParams: theme ? buildInputThemeParams(theme) : undefined, themeParams: theme ? buildInputThemeParams(theme) : undefined,
platform: WEB_APP_PLATFORM, platform: WEB_APP_PLATFORM,
startParam,
fromSwitchWebview: isFromSwitchWebView || undefined,
fromSideMenu: isFromSideMenu || undefined,
})); }));
return result?.url; return result?.url;

View File

@ -1104,6 +1104,10 @@ export function updater(update: Update) {
'@type': 'updateStealthMode', '@type': 'updateStealthMode',
stealthMode: buildApiStealthMode(update.stealthMode), stealthMode: buildApiStealthMode(update.stealthMode),
}); });
} else if (update instanceof GramJs.UpdateAttachMenuBots) {
onUpdate({
'@type': 'updateAttachMenuBots',
});
} else if (DEBUG) { } else if (DEBUG) {
const params = typeof update === 'object' && 'className' in update ? update.className : update; const params = typeof update === 'object' && 'className' in update ? update.className : update;
log('UNEXPECTED UPDATE', params); log('UNEXPECTED UPDATE', params);

View File

@ -661,6 +661,10 @@ export type ApiRequestSync = {
'@type': 'requestSync'; '@type': 'requestSync';
}; };
export type ApiUpdateAttachMenuBots = {
'@type': 'updateAttachMenuBots';
};
export type ApiUpdate = ( export type ApiUpdate = (
ApiUpdateReady | ApiUpdateSession | ApiUpdateWebAuthTokenFailed | ApiUpdateRequestUserUpdate | ApiUpdateReady | ApiUpdateSession | ApiUpdateWebAuthTokenFailed | ApiUpdateRequestUserUpdate |
ApiUpdateAuthorizationState | ApiUpdateAuthorizationError | ApiUpdateConnectionState | ApiUpdateCurrentUser | ApiUpdateAuthorizationState | ApiUpdateAuthorizationError | ApiUpdateConnectionState | ApiUpdateCurrentUser |
@ -689,7 +693,7 @@ export type ApiUpdate = (
ApiUpdatePinnedTopicsOrder | ApiUpdateTopic | ApiUpdateTopics | ApiUpdateRecentEmojiStatuses | ApiUpdatePinnedTopicsOrder | ApiUpdateTopic | ApiUpdateTopics | ApiUpdateRecentEmojiStatuses |
ApiUpdateRecentReactions | ApiUpdateStory | ApiUpdateReadStories | ApiUpdateDeleteStory | ApiUpdateSentStoryReaction | ApiUpdateRecentReactions | ApiUpdateStory | ApiUpdateReadStories | ApiUpdateDeleteStory | ApiUpdateSentStoryReaction |
ApiRequestReconnectApi | ApiRequestSync | ApiUpdateFetchingDifference | ApiUpdateChannelMessages | ApiRequestReconnectApi | ApiRequestSync | ApiUpdateFetchingDifference | ApiUpdateChannelMessages |
ApiUpdateStealthMode ApiUpdateStealthMode | ApiUpdateAttachMenuBots
); );
export type OnApiUpdate = (update: ApiUpdate) => void; export type OnApiUpdate = (update: ApiUpdate) => void;

View File

@ -74,14 +74,23 @@ export interface ApiUsername {
export type ApiChatType = typeof API_CHAT_TYPES[number]; export type ApiChatType = typeof API_CHAT_TYPES[number];
export type ApiAttachMenuPeerType = 'self' | ApiChatType; export type ApiAttachMenuPeerType = 'self' | ApiChatType;
export interface ApiAttachBot { type ApiAttachBotForMenu = {
isForAttachMenu: true;
attachMenuPeerTypes: ApiAttachMenuPeerType[];
};
type ApiAttachBotBase = {
id: string; id: string;
hasSettings?: boolean; hasSettings?: boolean;
shouldRequestWriteAccess?: boolean; shouldRequestWriteAccess?: boolean;
shortName: string; shortName: string;
peerTypes: ApiAttachMenuPeerType[]; isForSideMenu?: true;
isDisclaimerNeeded?: boolean;
icons: ApiAttachBotIcon[]; icons: ApiAttachBotIcon[];
} isInactive?: boolean;
};
export type ApiAttachBot = OptionalCombine<ApiAttachBotBase, ApiAttachBotForMenu>;
export interface ApiAttachBotIcon { export interface ApiAttachBotIcon {
name: string; name: string;

View File

@ -4,28 +4,15 @@ import React, {
} from '../../../lib/teact/teact'; } from '../../../lib/teact/teact';
import { getActions, withGlobal } from '../../../global'; import { getActions, withGlobal } from '../../../global';
import type { GlobalState, TabState } from '../../../global/types'; import type { GlobalState } from '../../../global/types';
import type { AnimationLevel, ISettings } from '../../../types'; import type { ISettings } from '../../../types';
import { LeftColumnContent, SettingsScreens } from '../../../types'; import { LeftColumnContent, SettingsScreens } from '../../../types';
import { import {
ANIMATION_LEVEL_MAX,
ANIMATION_LEVEL_MIN,
APP_NAME, APP_NAME,
ARCHIVED_FOLDER_ID,
BETA_CHANGELOG_URL,
DEBUG, DEBUG,
FEEDBACK_URL,
IS_BETA, IS_BETA,
IS_TEST,
PRODUCTION_HOSTNAME,
WEB_VERSION_BASE,
} from '../../../config'; } from '../../../config';
import {
INITIAL_PERFORMANCE_STATE_MAX,
INITIAL_PERFORMANCE_STATE_MID,
INITIAL_PERFORMANCE_STATE_MIN,
} from '../../../global/initialState';
import { import {
selectCanSetPasscode, selectCanSetPasscode,
selectCurrentMessageList, selectCurrentMessageList,
@ -36,14 +23,12 @@ import {
import buildClassName from '../../../util/buildClassName'; import buildClassName from '../../../util/buildClassName';
import captureEscKeyListener from '../../../util/captureEscKeyListener'; import captureEscKeyListener from '../../../util/captureEscKeyListener';
import { formatDateToString } from '../../../util/dateFormat'; import { formatDateToString } from '../../../util/dateFormat';
import { getPromptInstall } from '../../../util/installPrompt';
import { switchPermanentWebVersion } from '../../../util/permanentWebVersion';
import { IS_APP, IS_ELECTRON, IS_MAC_OS } from '../../../util/windowEnvironment'; 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';
import useElectronDrag from '../../../hooks/useElectronDrag'; import useElectronDrag from '../../../hooks/useElectronDrag';
import { useFolderManagerForUnreadCounters } from '../../../hooks/useFolderManager'; import useFlag from '../../../hooks/useFlag';
import { useFullscreenStatus } from '../../../hooks/useFullscreen'; import { useFullscreenStatus } from '../../../hooks/useFullscreen';
import { useHotkeys } from '../../../hooks/useHotkeys'; import { useHotkeys } from '../../../hooks/useHotkeys';
import useLang from '../../../hooks/useLang'; import useLang from '../../../hooks/useLang';
@ -54,12 +39,10 @@ import PickerSelectedItem from '../../common/PickerSelectedItem';
import StoryToggler from '../../story/StoryToggler'; import StoryToggler from '../../story/StoryToggler';
import Button from '../../ui/Button'; import Button from '../../ui/Button';
import DropdownMenu from '../../ui/DropdownMenu'; import DropdownMenu from '../../ui/DropdownMenu';
import MenuItem from '../../ui/MenuItem';
import SearchInput from '../../ui/SearchInput'; import SearchInput from '../../ui/SearchInput';
import ShowTransition from '../../ui/ShowTransition'; import ShowTransition from '../../ui/ShowTransition';
import Switcher from '../../ui/Switcher';
import Toggle from '../../ui/Toggle';
import ConnectionStatusOverlay from '../ConnectionStatusOverlay'; import ConnectionStatusOverlay from '../ConnectionStatusOverlay';
import LeftSideMenuItems from './LeftSideMenuItems';
import StatusButton from './StatusButton'; import StatusButton from './StatusButton';
import './LeftMainHeader.scss'; import './LeftMainHeader.scss';
@ -71,21 +54,19 @@ type OwnProps = {
isClosingSearch?: boolean; isClosingSearch?: boolean;
shouldSkipTransition?: boolean; shouldSkipTransition?: boolean;
onSearchQuery: (query: string) => void; onSearchQuery: (query: string) => void;
onSelectSettings: () => void; onSelectSettings: NoneToVoidFunction;
onSelectContacts: () => void; onSelectContacts: NoneToVoidFunction;
onSelectArchived: () => void; onSelectArchived: NoneToVoidFunction;
onReset: () => void; onReset: NoneToVoidFunction;
}; };
type StateProps = type StateProps =
{ {
searchQuery?: string; searchQuery?: string;
isLoading: boolean; isLoading: boolean;
currentUserId?: string;
globalSearchChatId?: string; globalSearchChatId?: string;
searchDate?: number; searchDate?: number;
theme: ISettings['theme']; theme: ISettings['theme'];
animationLevel: AnimationLevel;
isMessageListOpen: boolean; isMessageListOpen: boolean;
isCurrentUserPremium?: boolean; isCurrentUserPremium?: boolean;
isConnectionStatusMinimized: ISettings['isConnectionStatusMinimized']; isConnectionStatusMinimized: ISettings['isConnectionStatusMinimized'];
@ -93,8 +74,7 @@ type StateProps =
hasPasscode?: boolean; hasPasscode?: boolean;
canSetPasscode?: boolean; canSetPasscode?: boolean;
} }
& Pick<GlobalState, 'connectionState' | 'isSyncing' | 'isFetchingDifference' | 'archiveSettings'> & Pick<GlobalState, 'connectionState' | 'isSyncing' | 'isFetchingDifference'>;
& Pick<TabState, 'canInstall'>;
const CLEAR_DATE_SEARCH_PARAM = { date: undefined }; const CLEAR_DATE_SEARCH_PARAM = { date: undefined };
const CLEAR_CHAT_SEARCH_PARAM = { id: undefined }; const CLEAR_CHAT_SEARCH_PARAM = { id: undefined };
@ -103,21 +83,14 @@ const LeftMainHeader: FC<OwnProps & StateProps> = ({
shouldHideSearch, shouldHideSearch,
content, content,
contactsFilter, contactsFilter,
onSearchQuery,
isClosingSearch, isClosingSearch,
onSelectSettings,
onSelectContacts,
onSelectArchived,
onReset,
searchQuery, searchQuery,
isLoading, isLoading,
isCurrentUserPremium, isCurrentUserPremium,
shouldSkipTransition, shouldSkipTransition,
currentUserId,
globalSearchChatId, globalSearchChatId,
searchDate, searchDate,
theme, theme,
animationLevel,
connectionState, connectionState,
isSyncing, isSyncing,
isFetchingDifference, isFetchingDifference,
@ -126,24 +99,25 @@ const LeftMainHeader: FC<OwnProps & StateProps> = ({
areChatsLoaded, areChatsLoaded,
hasPasscode, hasPasscode,
canSetPasscode, canSetPasscode,
canInstall, onSearchQuery,
archiveSettings, onSelectSettings,
onSelectContacts,
onSelectArchived,
onReset,
}) => { }) => {
const { const {
openChat,
openChatWithInfo,
setGlobalSearchDate, setGlobalSearchDate,
setSettingOption, setSettingOption,
setGlobalSearchChatId, setGlobalSearchChatId,
openChatByUsername,
lockScreen, lockScreen,
requestNextSettingsScreen, requestNextSettingsScreen,
openUrl,
updatePerformanceSettings,
} = getActions(); } = getActions();
const lang = useLang(); const lang = useLang();
const { isMobile } = useAppLayout(); const { isMobile } = useAppLayout();
const [isBotMenuOpen, markBotMenuOpen, unmarkBotMenuOpen] = useFlag();
const hasMenu = content === LeftColumnContent.ChatList; const hasMenu = content === LeftColumnContent.ChatList;
const selectedSearchDate = useMemo(() => { const selectedSearchDate = useMemo(() => {
return searchDate return searchDate
@ -151,8 +125,6 @@ const LeftMainHeader: FC<OwnProps & StateProps> = ({
: undefined; : undefined;
}, [searchDate]); }, [searchDate]);
const archivedUnreadChatsCount = useFolderManagerForUnreadCounters()[ARCHIVED_FOLDER_ID]?.chatsCount || 0;
const { connectionStatus, connectionStatusText, connectionStatusPosition } = useConnectionStatus( const { connectionStatus, connectionStatusText, connectionStatusPosition } = useConnectionStatus(
lang, lang,
connectionState, connectionState,
@ -172,10 +144,6 @@ const LeftMainHeader: FC<OwnProps & StateProps> = ({
} }
}); });
const handleOpenMyStories = useLastCallback(() => {
openChatWithInfo({ id: currentUserId, shouldReplaceHistory: true, profileTab: 'stories' });
});
useHotkeys(canSetPasscode ? { useHotkeys(canSetPasscode ? {
'Ctrl+Shift+L': handleLockScreenHotkey, 'Ctrl+Shift+L': handleLockScreenHotkey,
'Alt+Shift+L': handleLockScreenHotkey, 'Alt+Shift+L': handleLockScreenHotkey,
@ -183,8 +151,6 @@ const LeftMainHeader: FC<OwnProps & StateProps> = ({
...(IS_APP && { 'Mod+L': handleLockScreenHotkey }), ...(IS_APP && { 'Mod+L': handleLockScreenHotkey }),
} : undefined); } : undefined);
const withOtherVersions = window.location.hostname === PRODUCTION_HOSTNAME || IS_TEST;
const MainButton: FC<{ onTrigger: () => void; isOpen?: boolean }> = useMemo(() => { const MainButton: FC<{ onTrigger: () => void; isOpen?: boolean }> = useMemo(() => {
return ({ onTrigger, isOpen }) => ( return ({ onTrigger, isOpen }) => (
<Button <Button
@ -217,49 +183,6 @@ const LeftMainHeader: FC<OwnProps & StateProps> = ({
setSettingOption({ isConnectionStatusMinimized: !isConnectionStatusMinimized }); setSettingOption({ isConnectionStatusMinimized: !isConnectionStatusMinimized });
}); });
const handleSelectSaved = useLastCallback(() => {
openChat({ id: currentUserId, shouldReplaceHistory: true });
});
const handleDarkModeToggle = useLastCallback((e: React.SyntheticEvent<HTMLElement>) => {
e.stopPropagation();
const newTheme = theme === 'light' ? 'dark' : 'light';
setSettingOption({ theme: newTheme });
setSettingOption({ shouldUseSystemTheme: false });
});
const handleAnimationLevelChange = useLastCallback((e: React.SyntheticEvent<HTMLElement>) => {
e.stopPropagation();
let newLevel = animationLevel + 1;
if (newLevel > ANIMATION_LEVEL_MAX) {
newLevel = ANIMATION_LEVEL_MIN;
}
const performanceSettings = newLevel === ANIMATION_LEVEL_MIN
? INITIAL_PERFORMANCE_STATE_MIN
: (newLevel === ANIMATION_LEVEL_MAX ? INITIAL_PERFORMANCE_STATE_MAX : INITIAL_PERFORMANCE_STATE_MID);
setSettingOption({ animationLevel: newLevel as AnimationLevel });
updatePerformanceSettings(performanceSettings);
});
const handleChangelogClick = useLastCallback(() => {
window.open(BETA_CHANGELOG_URL, '_blank', 'noopener');
});
const handleSwitchToWebK = useLastCallback(() => {
switchPermanentWebVersion('K');
});
const handleOpenTipsChat = useLastCallback(() => {
openChatByUsername({ username: lang('Settings.TipsUsername') });
});
const handleBugReportClick = useLastCallback(() => {
openUrl({ url: FEEDBACK_URL });
});
const handleLockScreen = useLastCallback(() => { const handleLockScreen = useLastCallback(() => {
lockScreen(); lockScreen();
}); });
@ -277,9 +200,6 @@ const LeftMainHeader: FC<OwnProps & StateProps> = ({
: lang('Search'); : lang('Search');
const versionString = IS_BETA ? `${APP_VERSION} Beta (${APP_REVISION})` : (DEBUG ? APP_REVISION : APP_VERSION); const versionString = IS_BETA ? `${APP_VERSION} Beta (${APP_REVISION})` : (DEBUG ? APP_REVISION : APP_VERSION);
const animationLevelValue = animationLevel !== ANIMATION_LEVEL_MIN
? (animationLevel === ANIMATION_LEVEL_MAX ? 'max' : 'mid')
: 'min';
const isFullscreen = useFullscreenStatus(); const isFullscreen = useFullscreenStatus();
@ -293,106 +213,6 @@ const LeftMainHeader: FC<OwnProps & StateProps> = ({
const headerRef = useRef<HTMLDivElement>(null); const headerRef = useRef<HTMLDivElement>(null);
useElectronDrag(headerRef); useElectronDrag(headerRef);
const menuItems = useMemo(() => (
<>
<MenuItem
icon="saved-messages"
onClick={handleSelectSaved}
>
{lang('SavedMessages')}
</MenuItem>
{archiveSettings.isHidden && (
<MenuItem
icon="archive"
onClick={onSelectArchived}
>
<span className="menu-item-name">{lang('ArchivedChats')}</span>
{archivedUnreadChatsCount > 0 && (
<div className="right-badge">{archivedUnreadChatsCount}</div>
)}
</MenuItem>
)}
<MenuItem
icon="user"
onClick={onSelectContacts}
>
{lang('Contacts')}
</MenuItem>
<MenuItem
icon="play-story"
onClick={handleOpenMyStories}
>
{lang('Settings.MyStories')}
</MenuItem>
<MenuItem
icon="settings"
onClick={onSelectSettings}
>
{lang('Settings')}
</MenuItem>
<MenuItem
icon="darkmode"
onClick={handleDarkModeToggle}
>
<span className="menu-item-name">{lang('lng_menu_night_mode')}</span>
<Switcher
id="darkmode"
label={lang(theme === 'dark' ? 'lng_settings_disable_night_theme' : 'lng_settings_enable_night_theme')}
checked={theme === 'dark'}
noAnimation
/>
</MenuItem>
<MenuItem
icon="animations"
onClick={handleAnimationLevelChange}
>
<span className="menu-item-name capitalize">{lang('Appearance.Animations').toLowerCase()}</span>
<Toggle value={animationLevelValue} />
</MenuItem>
<MenuItem
icon="help"
onClick={handleOpenTipsChat}
>
{lang('TelegramFeatures')}
</MenuItem>
<MenuItem
icon="bug"
onClick={handleBugReportClick}
>
Report Bug
</MenuItem>
{IS_BETA && (
<MenuItem
icon="permissions"
onClick={handleChangelogClick}
>
Beta Changelog
</MenuItem>
)}
{withOtherVersions && (
<MenuItem
icon="K"
isCharIcon
href={`${WEB_VERSION_BASE}k`}
onClick={handleSwitchToWebK}
>
Switch to K Version
</MenuItem>
)}
{canInstall && (
<MenuItem
icon="install"
onClick={getPromptInstall()}
>
Install App
</MenuItem>
)}
</>
), [
animationLevelValue, archiveSettings.isHidden, archivedUnreadChatsCount, canInstall, lang, onSelectArchived,
onSelectContacts, onSelectSettings, theme, withOtherVersions,
]);
const searchContent = useMemo(() => { const searchContent = useMemo(() => {
return ( return (
<> <>
@ -432,11 +252,18 @@ const LeftMainHeader: FC<OwnProps & StateProps> = ({
shouldHideSearch && lang.isRtl && 'right-aligned', shouldHideSearch && lang.isRtl && 'right-aligned',
shouldDisableDropdownMenuTransitionRef.current && lang.isRtl && 'disable-transition', shouldDisableDropdownMenuTransitionRef.current && lang.isRtl && 'disable-transition',
)} )}
forceOpen={isBotMenuOpen}
positionX={shouldHideSearch && lang.isRtl ? 'right' : 'left'} positionX={shouldHideSearch && lang.isRtl ? 'right' : 'left'}
transformOriginX={IS_ELECTRON && IS_MAC_OS && !isFullscreen ? 90 : undefined} transformOriginX={IS_ELECTRON && IS_MAC_OS && !isFullscreen ? 90 : undefined}
onTransitionEnd={lang.isRtl ? handleDropdownMenuTransitionEnd : undefined} onTransitionEnd={lang.isRtl ? handleDropdownMenuTransitionEnd : undefined}
> >
{menuItems} <LeftSideMenuItems
onSelectArchived={onSelectArchived}
onSelectContacts={onSelectContacts}
onSelectSettings={onSelectSettings}
onBotMenuOpened={markBotMenuOpen}
onBotMenuClosed={unmarkBotMenuOpen}
/>
</DropdownMenu> </DropdownMenu>
<SearchInput <SearchInput
inputId="telegram-search-input" inputId="telegram-search-input"
@ -498,18 +325,16 @@ export default memo(withGlobal<OwnProps>(
query: searchQuery, fetchingStatus, chatId, date, query: searchQuery, fetchingStatus, chatId, date,
} = tabState.globalSearch; } = tabState.globalSearch;
const { const {
currentUserId, connectionState, isSyncing, archiveSettings, isFetchingDifference, connectionState, isSyncing, isFetchingDifference,
} = global; } = global;
const { isConnectionStatusMinimized, animationLevel } = global.settings.byKey; const { isConnectionStatusMinimized } = global.settings.byKey;
return { return {
searchQuery, searchQuery,
isLoading: fetchingStatus ? Boolean(fetchingStatus.chats || fetchingStatus.messages) : false, isLoading: fetchingStatus ? Boolean(fetchingStatus.chats || fetchingStatus.messages) : false,
currentUserId,
globalSearchChatId: chatId, globalSearchChatId: chatId,
searchDate: date, searchDate: date,
theme: selectTheme(global), theme: selectTheme(global),
animationLevel,
connectionState, connectionState,
isSyncing, isSyncing,
isFetchingDifference, isFetchingDifference,
@ -518,8 +343,6 @@ export default memo(withGlobal<OwnProps>(
isCurrentUserPremium: selectIsCurrentUserPremium(global), isCurrentUserPremium: selectIsCurrentUserPremium(global),
areChatsLoaded: Boolean(global.chats.listIds.active), areChatsLoaded: Boolean(global.chats.listIds.active),
hasPasscode: Boolean(global.passcode.hasPasscode), hasPasscode: Boolean(global.passcode.hasPasscode),
canInstall: Boolean(tabState.canInstall),
archiveSettings,
canSetPasscode: selectCanSetPasscode(global), canSetPasscode: selectCanSetPasscode(global),
}; };
}, },

View File

@ -0,0 +1,255 @@
import React, { memo, useMemo } from '../../../lib/teact/teact';
import { getActions, withGlobal } from '../../../global';
import type { GlobalState } from '../../../global/types';
import type { AnimationLevel, ThemeKey } from '../../../types';
import {
ANIMATION_LEVEL_MAX,
ANIMATION_LEVEL_MIN,
ARCHIVED_FOLDER_ID,
BETA_CHANGELOG_URL,
FEEDBACK_URL,
IS_BETA,
IS_TEST,
PRODUCTION_HOSTNAME,
WEB_VERSION_BASE,
} from '../../../config';
import {
INITIAL_PERFORMANCE_STATE_MAX,
INITIAL_PERFORMANCE_STATE_MID,
INITIAL_PERFORMANCE_STATE_MIN,
} from '../../../global/initialState';
import { selectTabState, selectTheme } from '../../../global/selectors';
import { getPromptInstall } from '../../../util/installPrompt';
import { switchPermanentWebVersion } from '../../../util/permanentWebVersion';
import { useFolderManagerForUnreadCounters } from '../../../hooks/useFolderManager';
import useLang from '../../../hooks/useLang';
import useLastCallback from '../../../hooks/useLastCallback';
import AttachBotItem from '../../middle/composer/AttachBotItem';
import MenuItem from '../../ui/MenuItem';
import Switcher from '../../ui/Switcher';
import Toggle from '../../ui/Toggle';
type OwnProps = {
onSelectSettings: NoneToVoidFunction;
onSelectContacts: NoneToVoidFunction;
onSelectArchived: NoneToVoidFunction;
onBotMenuOpened: NoneToVoidFunction;
onBotMenuClosed: NoneToVoidFunction;
};
type StateProps = {
animationLevel: AnimationLevel;
theme: ThemeKey;
canInstall?: boolean;
attachBots: GlobalState['attachMenu']['bots'];
} & Pick<GlobalState, 'currentUserId' | 'archiveSettings'>;
const LeftSideMenuItems = ({
currentUserId,
archiveSettings,
animationLevel,
theme,
canInstall,
attachBots,
onSelectArchived,
onSelectContacts,
onSelectSettings,
onBotMenuOpened,
onBotMenuClosed,
}: OwnProps & StateProps) => {
const {
openChat,
setSettingOption,
updatePerformanceSettings,
openChatByUsername,
openUrl,
openChatWithInfo,
} = getActions();
const lang = useLang();
const animationLevelValue = animationLevel !== ANIMATION_LEVEL_MIN
? (animationLevel === ANIMATION_LEVEL_MAX ? 'max' : 'mid') : 'min';
const withOtherVersions = window.location.hostname === PRODUCTION_HOSTNAME || IS_TEST;
const archivedUnreadChatsCount = useFolderManagerForUnreadCounters()[ARCHIVED_FOLDER_ID]?.chatsCount || 0;
const bots = useMemo(() => Object.values(attachBots).filter((bot) => bot.isForSideMenu), [attachBots]);
const handleSelectSaved = useLastCallback(() => {
openChat({ id: currentUserId, shouldReplaceHistory: true });
});
const handleDarkModeToggle = useLastCallback((e: React.SyntheticEvent<HTMLElement>) => {
e.stopPropagation();
const newTheme = theme === 'light' ? 'dark' : 'light';
setSettingOption({ theme: newTheme });
setSettingOption({ shouldUseSystemTheme: false });
});
const handleAnimationLevelChange = useLastCallback((e: React.SyntheticEvent<HTMLElement>) => {
e.stopPropagation();
let newLevel = animationLevel + 1;
if (newLevel > ANIMATION_LEVEL_MAX) {
newLevel = ANIMATION_LEVEL_MIN;
}
const performanceSettings = newLevel === ANIMATION_LEVEL_MIN
? INITIAL_PERFORMANCE_STATE_MIN
: (newLevel === ANIMATION_LEVEL_MAX ? INITIAL_PERFORMANCE_STATE_MAX : INITIAL_PERFORMANCE_STATE_MID);
setSettingOption({ animationLevel: newLevel as AnimationLevel });
updatePerformanceSettings(performanceSettings);
});
const handleChangelogClick = useLastCallback(() => {
window.open(BETA_CHANGELOG_URL, '_blank', 'noopener');
});
const handleSwitchToWebK = useLastCallback(() => {
switchPermanentWebVersion('K');
});
const handleOpenTipsChat = useLastCallback(() => {
openChatByUsername({ username: lang('Settings.TipsUsername') });
});
const handleBugReportClick = useLastCallback(() => {
openUrl({ url: FEEDBACK_URL });
});
const handleOpenMyStories = useLastCallback(() => {
openChatWithInfo({ id: currentUserId, shouldReplaceHistory: true, profileTab: 'stories' });
});
return (
<>
<MenuItem
icon="saved-messages"
onClick={handleSelectSaved}
>
{lang('SavedMessages')}
</MenuItem>
{archiveSettings.isHidden && (
<MenuItem
icon="archive"
onClick={onSelectArchived}
>
<span className="menu-item-name">{lang('ArchivedChats')}</span>
{archivedUnreadChatsCount > 0 && (
<div className="right-badge">{archivedUnreadChatsCount}</div>
)}
</MenuItem>
)}
<MenuItem
icon="user"
onClick={onSelectContacts}
>
{lang('Contacts')}
</MenuItem>
{bots.map((bot) => (
<AttachBotItem
bot={bot}
theme={theme}
isInSideMenu
onMenuOpened={onBotMenuOpened}
onMenuClosed={onBotMenuClosed}
/>
))}
<MenuItem
icon="play-story"
onClick={handleOpenMyStories}
>
{lang('Settings.MyStories')}
</MenuItem>
<MenuItem
icon="settings"
onClick={onSelectSettings}
>
{lang('Settings')}
</MenuItem>
<MenuItem
icon="darkmode"
onClick={handleDarkModeToggle}
>
<span className="menu-item-name">{lang('lng_menu_night_mode')}</span>
<Switcher
id="darkmode"
label={lang(theme === 'dark' ? 'lng_settings_disable_night_theme' : 'lng_settings_enable_night_theme')}
checked={theme === 'dark'}
noAnimation
/>
</MenuItem>
<MenuItem
icon="animations"
onClick={handleAnimationLevelChange}
>
<span className="menu-item-name capitalize">{lang('Appearance.Animations').toLowerCase()}</span>
<Toggle value={animationLevelValue} />
</MenuItem>
<MenuItem
icon="help"
onClick={handleOpenTipsChat}
>
{lang('TelegramFeatures')}
</MenuItem>
<MenuItem
icon="bug"
onClick={handleBugReportClick}
>
Report Bug
</MenuItem>
{IS_BETA && (
<MenuItem
icon="permissions"
onClick={handleChangelogClick}
>
Beta Changelog
</MenuItem>
)}
{withOtherVersions && (
<MenuItem
icon="K"
isCharIcon
href={`${WEB_VERSION_BASE}k`}
onClick={handleSwitchToWebK}
>
Switch to K Version
</MenuItem>
)}
{canInstall && (
<MenuItem
icon="install"
onClick={getPromptInstall()}
>
Install App
</MenuItem>
)}
</>
);
};
export default memo(withGlobal<OwnProps>(
(global): StateProps => {
const tabState = selectTabState(global);
const {
currentUserId, archiveSettings,
} = global;
const { animationLevel } = global.settings.byKey;
const attachBots = global.attachMenu.bots;
return {
currentUserId,
theme: selectTheme(global),
animationLevel,
canInstall: Boolean(tabState.canInstall),
archiveSettings,
attachBots,
};
},
)(LeftSideMenuItems));

View File

@ -10,7 +10,6 @@ import { getUserFullName } from '../../global/helpers';
import renderText from '../common/helpers/renderText'; import renderText from '../common/helpers/renderText';
import useLang from '../../hooks/useLang'; import useLang from '../../hooks/useLang';
import usePrevious from '../../hooks/usePrevious';
import Checkbox from '../ui/Checkbox'; import Checkbox from '../ui/Checkbox';
import ConfirmDialog from '../ui/ConfirmDialog'; import ConfirmDialog from '../ui/ConfirmDialog';
@ -27,11 +26,6 @@ const BotTrustModal: FC<OwnProps> = ({ bot, type, shouldRequestWriteAccess }) =>
const [isWriteAllowed, setIsWriteAllowed] = useState(shouldRequestWriteAccess || false); const [isWriteAllowed, setIsWriteAllowed] = useState(shouldRequestWriteAccess || false);
const lang = useLang(); const lang = useLang();
// Keep props a little bit longer, to show correct text on closing animation
const previousBot = usePrevious(bot, false);
const previousType = usePrevious(type, false);
const currentBot = bot || previousBot;
const currentType = type || previousType;
const handleBotTrustAccept = useCallback(() => { const handleBotTrustAccept = useCallback(() => {
markBotTrusted({ botId: bot!.id, isWriteAllowed }); markBotTrusted({ botId: bot!.id, isWriteAllowed });
@ -41,18 +35,18 @@ const BotTrustModal: FC<OwnProps> = ({ bot, type, shouldRequestWriteAccess }) =>
cancelBotTrustRequest(); cancelBotTrustRequest();
}, []); }, []);
const title = currentType === 'game' ? lang('AppName') : lang('BotOpenPageTitle'); const title = type === 'game' ? lang('AppName') : lang('BotOpenPageTitle');
const text = useMemo(() => { const text = useMemo(() => {
switch (currentType) { switch (type) {
case 'game': case 'game':
return lang('BotPermissionGameAlert', getUserFullName(currentBot)); return lang('BotPermissionGameAlert', getUserFullName(bot));
case 'webApp': case 'webApp':
return lang('BotOpenPageMessage', getUserFullName(currentBot)); return lang('BotOpenPageMessage', getUserFullName(bot));
case 'botApp': case 'botApp':
default: default:
return lang('BotWebViewStartPermission'); return lang('BotWebViewStartPermission');
} }
}, [currentBot, currentType, lang]); }, [bot, type, lang]);
return ( return (
<ConfirmDialog <ConfirmDialog
@ -67,7 +61,7 @@ const BotTrustModal: FC<OwnProps> = ({ bot, type, shouldRequestWriteAccess }) =>
className="dialog-checkbox" className="dialog-checkbox"
checked={isWriteAllowed} checked={isWriteAllowed}
label={renderText( label={renderText(
lang('WebApp.AddToAttachmentAllowMessages', currentBot?.firstName), lang('WebApp.AddToAttachmentAllowMessages', bot?.firstName),
['simple_markdown'], ['simple_markdown'],
)} )}
onCheck={setIsWriteAllowed} onCheck={setIsWriteAllowed}

View File

@ -13,13 +13,13 @@ import useLastCallback from '../../../hooks/useLastCallback';
import Menu from '../../ui/Menu'; import Menu from '../../ui/Menu';
import MenuItem from '../../ui/MenuItem'; import MenuItem from '../../ui/MenuItem';
import Portal from '../../ui/Portal';
import AttachBotIcon from './AttachBotIcon'; import AttachBotIcon from './AttachBotIcon';
type OwnProps = { type OwnProps = {
bot: ApiAttachBot; bot: ApiAttachBot;
theme: ISettings['theme']; theme: ISettings['theme'];
chatId: string; isInSideMenu?: true;
chatId?: string;
threadId?: number; threadId?: number;
onMenuOpened: VoidFunction; onMenuOpened: VoidFunction;
onMenuClosed: VoidFunction; onMenuClosed: VoidFunction;
@ -30,6 +30,7 @@ const AttachBotItem: FC<OwnProps> = ({
theme, theme,
chatId, chatId,
threadId, threadId,
isInSideMenu,
onMenuOpened, onMenuOpened,
onMenuClosed, onMenuClosed,
}) => { }) => {
@ -52,6 +53,15 @@ const AttachBotItem: FC<OwnProps> = ({
openMenu(); openMenu();
}); });
const handleClick = useLastCallback(() => {
callAttachBot({
bot,
chatId: chatId!,
threadId,
isFromSideMenu: isInSideMenu,
});
});
const handleCloseMenu = useLastCallback(() => { const handleCloseMenu = useLastCallback(() => {
closeMenu(); closeMenu();
onMenuClosed(); onMenuClosed();
@ -73,29 +83,23 @@ const AttachBotItem: FC<OwnProps> = ({
key={bot.id} key={bot.id}
customIcon={icon && <AttachBotIcon icon={icon} theme={theme} />} customIcon={icon && <AttachBotIcon icon={icon} theme={theme} />}
icon={!icon ? 'bots' : undefined} icon={!icon ? 'bots' : undefined}
// eslint-disable-next-line react/jsx-no-bind onClick={handleClick}
onClick={() => callAttachBot({
bot,
chatId,
threadId,
})}
onContextMenu={handleContextMenu} onContextMenu={handleContextMenu}
> >
{bot.shortName} {bot.shortName}
{menuPosition && ( {menuPosition && (
<Portal> <Menu
<Menu isOpen={isMenuOpen}
isOpen={isMenuOpen} positionX="right"
positionX="right" style={`left: ${menuPosition.x}px;top: ${menuPosition.y}px;`}
style={`left: ${menuPosition.x}px;top: ${menuPosition.y}px;`} className="bot-attach-context-menu"
className="bot-attach-context-menu" autoClose
autoClose withPortal
onClose={handleCloseMenu} onClose={handleCloseMenu}
onCloseAnimationEnd={handleCloseAnimationEnd} onCloseAnimationEnd={handleCloseAnimationEnd}
> >
<MenuItem icon="stop" destructive onClick={handleRemoveBot}>{lang('WebApp.RemoveBot')}</MenuItem> <MenuItem icon="stop" destructive onClick={handleRemoveBot}>{lang('WebApp.RemoveBot')}</MenuItem>
</Menu> </Menu>
</Portal>
)} )}
</MenuItem> </MenuItem>

View File

@ -44,11 +44,11 @@ export type OwnProps = {
attachBots?: GlobalState['attachMenu']['bots']; attachBots?: GlobalState['attachMenu']['bots'];
peerType?: ApiAttachMenuPeerType; peerType?: ApiAttachMenuPeerType;
shouldCollectDebugLogs?: boolean; shouldCollectDebugLogs?: boolean;
theme: ISettings['theme'];
onFileSelect: (files: File[], shouldSuggestCompression?: boolean) => void; onFileSelect: (files: File[], shouldSuggestCompression?: boolean) => void;
onPollCreate: NoneToVoidFunction; onPollCreate: NoneToVoidFunction;
onMenuOpen: NoneToVoidFunction; onMenuOpen: NoneToVoidFunction;
onMenuClose: NoneToVoidFunction; onMenuClose: NoneToVoidFunction;
theme: ISettings['theme'];
}; };
const AttachMenu: FC<OwnProps> = ({ const AttachMenu: FC<OwnProps> = ({
@ -64,12 +64,12 @@ const AttachMenu: FC<OwnProps> = ({
attachBots, attachBots,
peerType, peerType,
isScheduled, isScheduled,
theme,
shouldCollectDebugLogs,
onFileSelect, onFileSelect,
onMenuOpen, onMenuOpen,
onMenuClose, onMenuClose,
onPollCreate, onPollCreate,
theme,
shouldCollectDebugLogs,
}) => { }) => {
const [isAttachMenuOpen, openAttachMenu, closeAttachMenu] = useFlag(); const [isAttachMenuOpen, openAttachMenu, closeAttachMenu] = useFlag();
const [handleMouseEnter, handleMouseLeave, markMouseInside] = useMouseInside(isAttachMenuOpen, closeAttachMenu); const [handleMouseEnter, handleMouseLeave, markMouseInside] = useMouseInside(isAttachMenuOpen, closeAttachMenu);
@ -135,11 +135,11 @@ const AttachMenu: FC<OwnProps> = ({
const bots = useMemo(() => { const bots = useMemo(() => {
return attachBots return attachBots
? Object.values(attachBots).filter((bot) => { ? Object.values(attachBots).filter((bot) => {
if (!peerType) return false; if (!peerType || !bot.isForAttachMenu) return false;
if (peerType === 'bots' && bot.id === chatId && bot.peerTypes.includes('self')) { if (peerType === 'bots' && bot.id === chatId && bot.attachMenuPeerTypes.includes('self')) {
return true; return true;
} }
return bot.peerTypes.includes(peerType); return bot.attachMenuPeerTypes!.includes(peerType);
}) })
: undefined; : undefined;
}, [attachBots, chatId, peerType]); }, [attachBots, chatId, peerType]);

View File

@ -113,6 +113,7 @@ const InlineBotTooltip: FC<OwnProps> = ({
url: switchWebview!.url, url: switchWebview!.url,
buttonText: switchWebview!.text, buttonText: switchWebview!.text,
theme, theme,
isFromSwitchWebView: true,
}); });
}); });

View File

@ -1,15 +1,15 @@
import type { FC } from '../../../lib/teact/teact'; import type { FC } from '../../../lib/teact/teact';
import React, { import React, {
memo, useCallback, useEffect, useState, memo, useCallback, useEffect, useMemo, useState,
} from '../../../lib/teact/teact'; } from '../../../lib/teact/teact';
import { getActions } from '../../../global'; import { getActions } from '../../../global';
import type { ApiAttachBot } from '../../../api/types'; import type { ApiAttachBot } from '../../../api/types';
import { MINI_APP_TOS_URL } from '../../../config';
import renderText from '../../common/helpers/renderText'; import renderText from '../../common/helpers/renderText';
import useLang from '../../../hooks/useLang'; import useLang from '../../../hooks/useLang';
import usePrevious from '../../../hooks/usePrevious';
import Checkbox from '../../ui/Checkbox'; import Checkbox from '../../ui/Checkbox';
import ConfirmDialog from '../../ui/ConfirmDialog'; import ConfirmDialog from '../../ui/ConfirmDialog';
@ -22,44 +22,51 @@ const AttachBotInstallModal: FC<OwnProps> = ({
bot, bot,
}) => { }) => {
const { confirmAttachBotInstall, cancelAttachBotInstall } = getActions(); const { confirmAttachBotInstall, cancelAttachBotInstall } = getActions();
const [isWriteAllowed, setIsWriteAllowed] = useState(bot?.shouldRequestWriteAccess || false); const [isTosAccepted, setIsTosAccepted] = useState(false);
const lang = useLang(); const lang = useLang();
const prevBot = usePrevious(bot);
const renderingBot = bot || prevBot;
const handleConfirm = useCallback(() => { const handleConfirm = useCallback(() => {
confirmAttachBotInstall({ confirmAttachBotInstall({
isWriteAllowed, isWriteAllowed: Boolean(bot?.shouldRequestWriteAccess),
}); });
}, [confirmAttachBotInstall, isWriteAllowed]); }, [confirmAttachBotInstall, bot]);
// Reset on re-open // Reset on re-open
useEffect(() => { useEffect(() => {
if (bot) { if (bot) {
setIsWriteAllowed(bot.shouldRequestWriteAccess ?? false); setIsTosAccepted(false);
} }
}, [bot]); }, [bot]);
const tosLabel = useMemo(() => {
const base = lang('lng_mini_apps_disclaimer_button');
const split = base.split('{link}');
const linkText = lang('lng_mini_apps_disclaimer_link');
return [
split[0],
<a href={MINI_APP_TOS_URL} target="_blank" rel="noopener noreferrer">{linkText}</a>,
split[1],
];
}, [lang]);
return ( return (
<ConfirmDialog <ConfirmDialog
isOpen={Boolean(bot)} isOpen={Boolean(bot)}
onClose={cancelAttachBotInstall} onClose={cancelAttachBotInstall}
title={renderingBot?.shortName} title={lang('lng_mini_apps_disclaimer_title')}
confirmHandler={handleConfirm} confirmHandler={handleConfirm}
isConfirmDisabled={!isTosAccepted}
> >
{lang('WebApp.AddToAttachmentText', renderingBot?.shortName)} {renderText(lang('lng_mini_apps_disclaimer_text', bot?.shortName), ['simple_markdown'])}
{renderingBot?.shouldRequestWriteAccess && ( <Checkbox
<Checkbox className="dialog-checkbox"
className="dialog-checkbox" checked={isTosAccepted}
checked={isWriteAllowed} label={tosLabel}
label={renderText( onCheck={setIsTosAccepted}
lang('WebApp.AddToAttachmentAllowMessages', renderingBot?.shortName), />
['simple_markdown'], {bot?.isInactive && bot.isForSideMenu && (
)} renderText(lang('WebBot.Account.Desclaimer.Desc', bot?.shortName), ['simple_markdown'])
onCheck={setIsWriteAllowed}
/>
)} )}
</ConfirmDialog> </ConfirmDialog>
); );

View File

@ -1,10 +1,12 @@
.root { .root {
--color-transition: 0.25s ease-in-out;
:global { :global {
.modal-header { .modal-header {
color: var(--color-header-text);
border-bottom: 1px solid var(--color-dividers); border-bottom: 1px solid var(--color-dividers);
padding: 0.5rem; padding: 0.5rem;
transition: 0.25s ease-in-out background-color; transition: var(--color-transition) background-color, var(--color-transition) color;
} }
.modal-dialog { .modal-dialog {
@ -43,7 +45,14 @@
} }
} }
.more-button {
opacity: 0.75;
color: var(--color-header-text) !important;
transition: var(--color-transition) color;
}
.close-icon { .close-icon {
opacity: 0.75;
position: absolute; position: absolute;
transform: rotate(-45deg); transform: rotate(-45deg);
@ -53,8 +62,8 @@
width: 1.125rem; width: 1.125rem;
height: 0.125rem; height: 0.125rem;
border-radius: 0.125rem; border-radius: 0.125rem;
background-color: var(--color-text-secondary); background-color: var(--color-header-text);
transition: transform var(--slide-transition); transition: var(--slide-transition) transform, var(--color-transition) background-color;
} }
&::before, &::before,

View File

@ -15,6 +15,9 @@ import {
selectCurrentChat, selectTabState, selectTheme, selectUser, selectCurrentChat, selectTabState, selectTheme, selectUser,
} from '../../../global/selectors'; } from '../../../global/selectors';
import buildClassName from '../../../util/buildClassName'; import buildClassName from '../../../util/buildClassName';
import buildStyle from '../../../util/buildStyle';
import { getColorLuma } from '../../../util/colors';
import { hexToRgb } from '../../../util/switchTheme';
import { extractCurrentThemeParams, validateHexColor } from '../../../util/themeStyle'; import { extractCurrentThemeParams, validateHexColor } from '../../../util/themeStyle';
import { callApi } from '../../../api/gramjs'; import { callApi } from '../../../api/gramjs';
@ -65,6 +68,7 @@ const MAIN_BUTTON_ANIMATION_TIME = 250;
const PROLONG_INTERVAL = 45000; // 45s const PROLONG_INTERVAL = 45000; // 45s
const ANIMATION_WAIT = 400; const ANIMATION_WAIT = 400;
const POPUP_SEQUENTIAL_LIMIT = 3; const POPUP_SEQUENTIAL_LIMIT = 3;
const LUMA_THRESHOLD = 128;
const POPUP_RESET_DELAY = 2000; // 2s const POPUP_RESET_DELAY = 2000; // 2s
const SANDBOX_ATTRIBUTES = [ const SANDBOX_ATTRIBUTES = [
'allow-scripts', 'allow-scripts',
@ -366,11 +370,18 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
} }
if (eventType === 'web_app_set_header_color') { if (eventType === 'web_app_set_header_color') {
const themeParams = extractCurrentThemeParams(); if (eventData.color_key) {
const key = eventData.color_key; const themeParams = extractCurrentThemeParams();
const newColor = themeParams[key]; const key = eventData.color_key;
const color = validateHexColor(newColor) ? newColor : themeParams.bg_color; const newColor = themeParams[key];
setHeaderColor(color); const color = validateHexColor(newColor) ? newColor : headerColor;
setHeaderColor(color);
}
if (eventData.color) {
const color = validateHexColor(eventData.color) ? eventData.color : headerColor;
setHeaderColor(color);
}
} }
if (eventType === 'web_app_data_send') { if (eventType === 'web_app_data_send') {
@ -459,7 +470,7 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
ripple={!isMobile} ripple={!isMobile}
size="smaller" size="smaller"
color="translucent" color="translucent"
className={isMenuOpen ? 'active' : ''} className={buildClassName(styles.moreButton, isMenuOpen && 'active')}
onClick={onTrigger} onClick={onTrigger}
ariaLabel="More actions" ariaLabel="More actions"
> >
@ -473,9 +484,23 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
isBackButtonVisible && styles.stateBack, isBackButtonVisible && styles.stateBack,
); );
const headerTextVar = useMemo(() => {
if (!headerColor) return undefined;
const { r, g, b } = hexToRgb(headerColor);
const luma = getColorLuma([r, g, b]);
const adaptedLuma = theme === 'dark' ? 255 - luma : luma;
return adaptedLuma > LUMA_THRESHOLD ? 'color-text' : 'color-background';
}, [headerColor, theme]);
function renderHeader() { function renderHeader() {
return ( return (
<div className="modal-header" style={`background-color: ${headerColor}`}> <div
className="modal-header"
style={buildStyle(
headerColor && `background-color: ${headerColor}`,
headerTextVar && `--color-header-text: var(--${headerTextVar})`,
)}
>
<Button <Button
round round
color="translucent" color="translucent"

View File

@ -13,34 +13,36 @@ import Modal from './Modal';
type OwnProps = { type OwnProps = {
isOpen: boolean; isOpen: boolean;
onClose: () => void;
onCloseAnimationEnd?: () => void;
title?: string; title?: string;
header?: TeactNode; header?: TeactNode;
textParts?: TextPart; textParts?: TextPart;
text?: string; text?: string;
confirmLabel?: string; confirmLabel?: string;
confirmHandler: () => void;
confirmIsDestructive?: boolean; confirmIsDestructive?: boolean;
isConfirmDisabled?: boolean;
areButtonsInColumn?: boolean; areButtonsInColumn?: boolean;
className?: string; className?: string;
children?: React.ReactNode; children?: React.ReactNode;
confirmHandler: NoneToVoidFunction;
onClose: NoneToVoidFunction;
onCloseAnimationEnd?: NoneToVoidFunction;
}; };
const ConfirmDialog: FC<OwnProps> = ({ const ConfirmDialog: FC<OwnProps> = ({
isOpen, isOpen,
onClose,
onCloseAnimationEnd,
title, title,
header, header,
text, text,
textParts, textParts,
confirmLabel = 'Confirm', confirmLabel = 'Confirm',
confirmHandler,
confirmIsDestructive, confirmIsDestructive,
isConfirmDisabled,
areButtonsInColumn, areButtonsInColumn,
className, className,
children, children,
confirmHandler,
onClose,
onCloseAnimationEnd,
}) => { }) => {
const lang = useLang(); const lang = useLang();
@ -76,6 +78,7 @@ const ConfirmDialog: FC<OwnProps> = ({
isText isText
onClick={confirmHandler} onClick={confirmHandler}
color={confirmIsDestructive ? 'danger' : 'primary'} color={confirmIsDestructive ? 'danger' : 'primary'}
disabled={isConfirmDisabled}
> >
{confirmLabel} {confirmLabel}
</Button> </Button>

View File

@ -51,7 +51,7 @@ export const CUSTOM_EMOJI_PREVIEW_CACHE_DISABLED = false;
export const CUSTOM_EMOJI_PREVIEW_CACHE_NAME = 'tt-custom-emoji-preview'; export const CUSTOM_EMOJI_PREVIEW_CACHE_NAME = 'tt-custom-emoji-preview';
export const MEDIA_CACHE_MAX_BYTES = 512 * 1024; // 512 KB export const MEDIA_CACHE_MAX_BYTES = 512 * 1024; // 512 KB
export const CUSTOM_BG_CACHE_NAME = 'tt-custom-bg'; export const CUSTOM_BG_CACHE_NAME = 'tt-custom-bg';
export const LANG_CACHE_NAME = 'tt-lang-packs-v22'; export const LANG_CACHE_NAME = 'tt-lang-packs-v23';
export const ASSET_CACHE_NAME = 'tt-assets'; export const ASSET_CACHE_NAME = 'tt-assets';
export const AUTODOWNLOAD_FILESIZE_MB_LIMITS = [1, 5, 10, 50, 100, 500]; export const AUTODOWNLOAD_FILESIZE_MB_LIMITS = [1, 5, 10, 50, 100, 500];
export const DATA_BROADCAST_CHANNEL_NAME = 'tt-global'; export const DATA_BROADCAST_CHANNEL_NAME = 'tt-global';
@ -293,6 +293,7 @@ export const DEFAULT_LANG_CODE = 'en';
export const DEFAULT_LANG_PACK = 'android'; export const DEFAULT_LANG_PACK = 'android';
export const LANG_PACKS = ['android', 'ios', 'tdesktop', 'macos'] as const; export const LANG_PACKS = ['android', 'ios', 'tdesktop', 'macos'] as const;
export const FEEDBACK_URL = 'https://bugs.telegram.org/?tag_ids=41&sort=time'; export const FEEDBACK_URL = 'https://bugs.telegram.org/?tag_ids=41&sort=time';
export const MINI_APP_TOS_URL = 'https://telegram.org/tos/mini-apps';
export const GENERAL_TOPIC_ID = 1; export const GENERAL_TOPIC_ID = 1;
export const STORY_EXPIRE_PERIOD = 86400; // 1 day export const STORY_EXPIRE_PERIOD = 86400; // 1 day
export const STORY_VIEWERS_EXPIRE_PERIOD = 86400; // 1 day export const STORY_VIEWERS_EXPIRE_PERIOD = 86400; // 1 day

View File

@ -452,7 +452,7 @@ addActionHandler('sharePhoneWithBot', async (global, actions, payload): Promise<
addActionHandler('requestSimpleWebView', async (global, actions, payload): Promise<void> => { addActionHandler('requestSimpleWebView', async (global, actions, payload): Promise<void> => {
const { const {
url, botId, theme, buttonText, url, botId, theme, buttonText, isFromSideMenu, isFromSwitchWebView, startParam,
tabId = getCurrentTabId(), tabId = getCurrentTabId(),
} = payload; } = payload;
@ -474,7 +474,14 @@ addActionHandler('requestSimpleWebView', async (global, actions, payload): Promi
return; return;
} }
const webViewUrl = await callApi('requestSimpleWebView', { url, bot, theme }); const webViewUrl = await callApi('requestSimpleWebView', {
url,
bot,
theme,
startParam,
isFromSideMenu,
isFromSwitchWebView,
});
if (!webViewUrl) { if (!webViewUrl) {
return; return;
} }
@ -724,16 +731,8 @@ addActionHandler('toggleAttachBot', async (global, actions, payload): Promise<vo
if (!bot) return; if (!bot) return;
await toggleAttachBot(global, bot, isEnabled, isWriteAllowed);
});
async function toggleAttachBot<T extends GlobalState>(
global: T, bot: ApiUser, isEnabled: boolean, isWriteAllowed?: boolean,
) {
await callApi('toggleAttachBot', { bot, isWriteAllowed, isEnabled }); await callApi('toggleAttachBot', { bot, isWriteAllowed, isEnabled });
global = getGlobal(); });
await loadAttachBots(global);
}
async function loadAttachBots<T extends GlobalState>(global: T, hash?: string) { async function loadAttachBots<T extends GlobalState>(global: T, hash?: string) {
const result = await callApi('loadAttachBots', { hash }); const result = await callApi('loadAttachBots', { hash });
@ -755,33 +754,52 @@ async function loadAttachBots<T extends GlobalState>(global: T, hash?: string) {
addActionHandler('callAttachBot', (global, actions, payload): ActionReturnType => { addActionHandler('callAttachBot', (global, actions, payload): ActionReturnType => {
const { const {
chatId, bot, url, startParam, threadId, chatId, bot, url, startParam, threadId, isFromSideMenu,
tabId = getCurrentTabId(), tabId = getCurrentTabId(),
} = payload; } = payload;
const isFromBotMenu = !bot; const isFromBotMenu = !bot;
if (!isFromBotMenu && !global.attachMenu.bots[bot.id]) { if ((!isFromBotMenu && !global.attachMenu.bots[bot.id])
|| (isFromSideMenu && (bot?.isInactive || bot?.isDisclaimerNeeded))) {
return updateTabState(global, { return updateTabState(global, {
requestedAttachBotInstall: { requestedAttachBotInstall: {
bot, bot,
onConfirm: { onConfirm: {
action: 'callAttachBot', action: 'callAttachBot',
payload, payload: {
...payload,
bot: {
...bot,
isInactive: false,
isDisclaimerNeeded: false,
},
},
}, },
}, },
}, tabId); }, tabId);
} }
const theme = extractCurrentThemeParams(); const theme = extractCurrentThemeParams();
actions.openChat({ id: chatId, threadId, tabId }); if (isFromSideMenu) {
actions.requestWebView({ actions.requestSimpleWebView({
url, botId: bot!.id,
peerId: chatId, buttonText: '',
botId: isFromBotMenu ? chatId : bot.id, isFromSideMenu: true,
theme, theme,
buttonText: '', tabId,
isFromBotMenu, });
startParam, } else {
tabId, actions.openChat({ id: chatId, threadId, tabId });
}); actions.requestWebView({
url,
peerId: chatId,
botId: isFromBotMenu ? chatId : bot.id,
theme,
buttonText: '',
isFromBotMenu,
startParam,
tabId,
});
}
return undefined; return undefined;
}); });
@ -800,7 +818,7 @@ addActionHandler('confirmAttachBotInstall', async (global, actions, payload): Pr
const botUser = selectUser(global, bot.id); const botUser = selectUser(global, bot.id);
if (!botUser) return; if (!botUser) return;
await toggleAttachBot(global, botUser, true, isWriteAllowed); await callApi('toggleAttachBot', { bot: botUser, isWriteAllowed, isEnabled: true });
if (onConfirm) { if (onConfirm) {
const { action, payload: actionPayload } = onConfirm; const { action, payload: actionPayload } = onConfirm;
// @ts-ignore // @ts-ignore
@ -821,11 +839,11 @@ addActionHandler('requestAttachBotInChat', (global, actions, payload): ActionRet
} = payload; } = payload;
const currentChatId = selectCurrentMessageList(global, tabId)?.chatId; const currentChatId = selectCurrentMessageList(global, tabId)?.chatId;
const supportedFilters = bot.peerTypes.filter((type): type is ApiChatType => ( const supportedFilters = bot.attachMenuPeerTypes?.filter((type): type is ApiChatType => (
type !== 'self' && filter.includes(type) type !== 'self' && filter.includes(type)
)); ));
if (!supportedFilters.length) { if (!supportedFilters?.length) {
actions.callAttachBot({ actions.callAttachBot({
chatId: currentChatId || bot.id, chatId: currentChatId || bot.id,
bot, bot,

View File

@ -141,6 +141,10 @@ addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => {
global = updateStealthMode(global, update.stealthMode); global = updateStealthMode(global, update.stealthMode);
setGlobal(global); setGlobal(global);
break; break;
case 'updateAttachMenuBots':
actions.loadAttachBots({ hash: global.attachMenu.hash });
break;
} }
return undefined; return undefined;

View File

@ -2346,10 +2346,13 @@ export interface ActionPayloads {
threadId?: number; threadId?: number;
} & WithTabId; } & WithTabId;
requestSimpleWebView: { requestSimpleWebView: {
url: string; url?: string;
botId: string; botId: string;
buttonText: string; buttonText: string;
theme?: ApiThemeParameters; theme?: ApiThemeParameters;
startParam?: string;
isFromSwitchWebView?: boolean;
isFromSideMenu?: boolean;
} & WithTabId; } & WithTabId;
requestAppWebView: { requestAppWebView: {
botId: string; botId: string;
@ -2407,6 +2410,7 @@ export interface ActionPayloads {
bot?: ApiAttachBot; bot?: ApiAttachBot;
url?: string; url?: string;
startParam?: string; startParam?: string;
isFromSideMenu?: boolean;
} & WithTabId; } & WithTabId;
requestBotUrlAuth: { requestBotUrlAuth: {

View File

@ -1,6 +1,6 @@
const api = require('./api'); const api = require('./api');
const LAYER = 162; const LAYER = 163;
const tlobjects = {}; const tlobjects = {};
for (const tl of Object.values(api)) { for (const tl of Object.values(api)) {

View File

@ -86,7 +86,7 @@ namespace Api {
export type TypeImportedContact = ImportedContact; export type TypeImportedContact = ImportedContact;
export type TypeContactStatus = ContactStatus; export type TypeContactStatus = ContactStatus;
export type TypeMessagesFilter = InputMessagesFilterEmpty | InputMessagesFilterPhotos | InputMessagesFilterVideo | InputMessagesFilterPhotoVideo | InputMessagesFilterDocument | InputMessagesFilterUrl | InputMessagesFilterGif | InputMessagesFilterVoice | InputMessagesFilterMusic | InputMessagesFilterChatPhotos | InputMessagesFilterPhoneCalls | InputMessagesFilterRoundVoice | InputMessagesFilterRoundVideo | InputMessagesFilterMyMentions | InputMessagesFilterGeo | InputMessagesFilterContacts | InputMessagesFilterPinned; export type TypeMessagesFilter = InputMessagesFilterEmpty | InputMessagesFilterPhotos | InputMessagesFilterVideo | InputMessagesFilterPhotoVideo | InputMessagesFilterDocument | InputMessagesFilterUrl | InputMessagesFilterGif | InputMessagesFilterVoice | InputMessagesFilterMusic | InputMessagesFilterChatPhotos | InputMessagesFilterPhoneCalls | InputMessagesFilterRoundVoice | InputMessagesFilterRoundVideo | InputMessagesFilterMyMentions | InputMessagesFilterGeo | InputMessagesFilterContacts | InputMessagesFilterPinned;
export type TypeUpdate = UpdateNewMessage | UpdateMessageID | UpdateDeleteMessages | UpdateUserTyping | UpdateChatUserTyping | UpdateChatParticipants | UpdateUserStatus | UpdateUserName | UpdateNewEncryptedMessage | UpdateEncryptedChatTyping | UpdateEncryption | UpdateEncryptedMessagesRead | UpdateChatParticipantAdd | UpdateChatParticipantDelete | UpdateDcOptions | UpdateNotifySettings | UpdateServiceNotification | UpdatePrivacy | UpdateUserPhone | UpdateReadHistoryInbox | UpdateReadHistoryOutbox | UpdateWebPage | UpdateReadMessagesContents | UpdateChannelTooLong | UpdateChannel | UpdateNewChannelMessage | UpdateReadChannelInbox | UpdateDeleteChannelMessages | UpdateChannelMessageViews | UpdateChatParticipantAdmin | UpdateNewStickerSet | UpdateStickerSetsOrder | UpdateStickerSets | UpdateSavedGifs | UpdateBotInlineQuery | UpdateBotInlineSend | UpdateEditChannelMessage | UpdateBotCallbackQuery | UpdateEditMessage | UpdateInlineBotCallbackQuery | UpdateReadChannelOutbox | UpdateDraftMessage | UpdateReadFeaturedStickers | UpdateRecentStickers | UpdateConfig | UpdatePtsChanged | UpdateChannelWebPage | UpdateDialogPinned | UpdatePinnedDialogs | UpdateBotWebhookJSON | UpdateBotWebhookJSONQuery | UpdateBotShippingQuery | UpdateBotPrecheckoutQuery | UpdatePhoneCall | UpdateLangPackTooLong | UpdateLangPack | UpdateFavedStickers | UpdateChannelReadMessagesContents | UpdateContactsReset | UpdateChannelAvailableMessages | UpdateDialogUnreadMark | UpdateMessagePoll | UpdateChatDefaultBannedRights | UpdateFolderPeers | UpdatePeerSettings | UpdatePeerLocated | UpdateNewScheduledMessage | UpdateDeleteScheduledMessages | UpdateTheme | UpdateGeoLiveViewed | UpdateLoginToken | UpdateMessagePollVote | UpdateDialogFilter | UpdateDialogFilterOrder | UpdateDialogFilters | UpdatePhoneCallSignalingData | UpdateChannelMessageForwards | UpdateReadChannelDiscussionInbox | UpdateReadChannelDiscussionOutbox | UpdatePeerBlocked | UpdateChannelUserTyping | UpdatePinnedMessages | UpdatePinnedChannelMessages | UpdateChat | UpdateGroupCallParticipants | UpdateGroupCall | UpdatePeerHistoryTTL | UpdateChatParticipant | UpdateChannelParticipant | UpdateBotStopped | UpdateGroupCallConnection | UpdateBotCommands | UpdatePendingJoinRequests | UpdateBotChatInviteRequester | UpdateMessageReactions | UpdateAttachMenuBots | UpdateWebViewResultSent | UpdateBotMenuButton | UpdateSavedRingtones | UpdateTranscribedAudio | UpdateReadFeaturedEmojiStickers | UpdateUserEmojiStatus | UpdateRecentEmojiStatuses | UpdateRecentReactions | UpdateMoveStickerSetToTop | UpdateMessageExtendedMedia | UpdateChannelPinnedTopic | UpdateChannelPinnedTopics | UpdateUser | UpdateAutoSaveSettings | UpdateGroupInvitePrivacyForbidden | UpdateStory | UpdateReadStories | UpdateStoryID | UpdateStoriesStealthMode | UpdateSentStoryReaction; export type TypeUpdate = UpdateNewMessage | UpdateMessageID | UpdateDeleteMessages | UpdateUserTyping | UpdateChatUserTyping | UpdateChatParticipants | UpdateUserStatus | UpdateUserName | UpdateNewAuthorization | UpdateNewEncryptedMessage | UpdateEncryptedChatTyping | UpdateEncryption | UpdateEncryptedMessagesRead | UpdateChatParticipantAdd | UpdateChatParticipantDelete | UpdateDcOptions | UpdateNotifySettings | UpdateServiceNotification | UpdatePrivacy | UpdateUserPhone | UpdateReadHistoryInbox | UpdateReadHistoryOutbox | UpdateWebPage | UpdateReadMessagesContents | UpdateChannelTooLong | UpdateChannel | UpdateNewChannelMessage | UpdateReadChannelInbox | UpdateDeleteChannelMessages | UpdateChannelMessageViews | UpdateChatParticipantAdmin | UpdateNewStickerSet | UpdateStickerSetsOrder | UpdateStickerSets | UpdateSavedGifs | UpdateBotInlineQuery | UpdateBotInlineSend | UpdateEditChannelMessage | UpdateBotCallbackQuery | UpdateEditMessage | UpdateInlineBotCallbackQuery | UpdateReadChannelOutbox | UpdateDraftMessage | UpdateReadFeaturedStickers | UpdateRecentStickers | UpdateConfig | UpdatePtsChanged | UpdateChannelWebPage | UpdateDialogPinned | UpdatePinnedDialogs | UpdateBotWebhookJSON | UpdateBotWebhookJSONQuery | UpdateBotShippingQuery | UpdateBotPrecheckoutQuery | UpdatePhoneCall | UpdateLangPackTooLong | UpdateLangPack | UpdateFavedStickers | UpdateChannelReadMessagesContents | UpdateContactsReset | UpdateChannelAvailableMessages | UpdateDialogUnreadMark | UpdateMessagePoll | UpdateChatDefaultBannedRights | UpdateFolderPeers | UpdatePeerSettings | UpdatePeerLocated | UpdateNewScheduledMessage | UpdateDeleteScheduledMessages | UpdateTheme | UpdateGeoLiveViewed | UpdateLoginToken | UpdateMessagePollVote | UpdateDialogFilter | UpdateDialogFilterOrder | UpdateDialogFilters | UpdatePhoneCallSignalingData | UpdateChannelMessageForwards | UpdateReadChannelDiscussionInbox | UpdateReadChannelDiscussionOutbox | UpdatePeerBlocked | UpdateChannelUserTyping | UpdatePinnedMessages | UpdatePinnedChannelMessages | UpdateChat | UpdateGroupCallParticipants | UpdateGroupCall | UpdatePeerHistoryTTL | UpdateChatParticipant | UpdateChannelParticipant | UpdateBotStopped | UpdateGroupCallConnection | UpdateBotCommands | UpdatePendingJoinRequests | UpdateBotChatInviteRequester | UpdateMessageReactions | UpdateAttachMenuBots | UpdateWebViewResultSent | UpdateBotMenuButton | UpdateSavedRingtones | UpdateTranscribedAudio | UpdateReadFeaturedEmojiStickers | UpdateUserEmojiStatus | UpdateRecentEmojiStatuses | UpdateRecentReactions | UpdateMoveStickerSetToTop | UpdateMessageExtendedMedia | UpdateChannelPinnedTopic | UpdateChannelPinnedTopics | UpdateUser | UpdateAutoSaveSettings | UpdateGroupInvitePrivacyForbidden | UpdateStory | UpdateReadStories | UpdateStoryID | UpdateStoriesStealthMode | UpdateSentStoryReaction;
export type TypeUpdates = UpdatesTooLong | UpdateShortMessage | UpdateShortChatMessage | UpdateShort | UpdatesCombined | Updates | UpdateShortSentMessage; export type TypeUpdates = UpdatesTooLong | UpdateShortMessage | UpdateShortChatMessage | UpdateShort | UpdatesCombined | Updates | UpdateShortSentMessage;
export type TypeDcOption = DcOption; export type TypeDcOption = DcOption;
export type TypeConfig = Config; export type TypeConfig = Config;
@ -2371,6 +2371,21 @@ namespace Api {
lastName: string; lastName: string;
usernames: Api.TypeUsername[]; usernames: Api.TypeUsername[];
}; };
export class UpdateNewAuthorization extends VirtualClass<{
// flags: undefined;
unconfirmed?: true;
hash: long;
date?: int;
device?: string;
location?: string;
}> {
// flags: undefined;
unconfirmed?: true;
hash: long;
date?: int;
device?: string;
location?: string;
};
export class UpdateNewEncryptedMessage extends VirtualClass<{ export class UpdateNewEncryptedMessage extends VirtualClass<{
message: Api.TypeEncryptedMessage; message: Api.TypeEncryptedMessage;
qts: int; qts: int;
@ -2502,13 +2517,17 @@ namespace Api {
ptsCount: int; ptsCount: int;
}; };
export class UpdateReadMessagesContents extends VirtualClass<{ export class UpdateReadMessagesContents extends VirtualClass<{
// flags: undefined;
messages: int[]; messages: int[];
pts: int; pts: int;
ptsCount: int; ptsCount: int;
date?: int;
}> { }> {
// flags: undefined;
messages: int[]; messages: int[];
pts: int; pts: int;
ptsCount: int; ptsCount: int;
date?: int;
}; };
export class UpdateChannelTooLong extends VirtualClass<{ export class UpdateChannelTooLong extends VirtualClass<{
// flags: undefined; // flags: undefined;
@ -4013,6 +4032,7 @@ namespace Api {
passwordPending?: true; passwordPending?: true;
encryptedRequestsDisabled?: true; encryptedRequestsDisabled?: true;
callRequestsDisabled?: true; callRequestsDisabled?: true;
unconfirmed?: true;
hash: long; hash: long;
deviceModel: string; deviceModel: string;
platform: string; platform: string;
@ -4032,6 +4052,7 @@ namespace Api {
passwordPending?: true; passwordPending?: true;
encryptedRequestsDisabled?: true; encryptedRequestsDisabled?: true;
callRequestsDisabled?: true; callRequestsDisabled?: true;
unconfirmed?: true;
hash: long; hash: long;
deviceModel: string; deviceModel: string;
platform: string; platform: string;
@ -7812,18 +7833,24 @@ namespace Api {
inactive?: true; inactive?: true;
hasSettings?: true; hasSettings?: true;
requestWriteAccess?: true; requestWriteAccess?: true;
showInAttachMenu?: true;
showInSideMenu?: true;
sideMenuDisclaimerNeeded?: true;
botId: long; botId: long;
shortName: string; shortName: string;
peerTypes: Api.TypeAttachMenuPeerType[]; peerTypes?: Api.TypeAttachMenuPeerType[];
icons: Api.TypeAttachMenuBotIcon[]; icons: Api.TypeAttachMenuBotIcon[];
}> { }> {
// flags: undefined; // flags: undefined;
inactive?: true; inactive?: true;
hasSettings?: true; hasSettings?: true;
requestWriteAccess?: true; requestWriteAccess?: true;
showInAttachMenu?: true;
showInSideMenu?: true;
sideMenuDisclaimerNeeded?: true;
botId: long; botId: long;
shortName: string; shortName: string;
peerTypes: Api.TypeAttachMenuPeerType[]; peerTypes?: Api.TypeAttachMenuPeerType[];
icons: Api.TypeAttachMenuBotIcon[]; icons: Api.TypeAttachMenuBotIcon[];
}; };
export class AttachMenuBotsNotModified extends VirtualClass<void> {}; export class AttachMenuBotsNotModified extends VirtualClass<void> {};
@ -9669,11 +9696,13 @@ namespace Api {
// flags: undefined; // flags: undefined;
inactive?: true; inactive?: true;
requestWriteAccess?: true; requestWriteAccess?: true;
hasSettings?: true;
app: Api.TypeBotApp; app: Api.TypeBotApp;
}> { }> {
// flags: undefined; // flags: undefined;
inactive?: true; inactive?: true;
requestWriteAccess?: true; requestWriteAccess?: true;
hasSettings?: true;
app: Api.TypeBotApp; app: Api.TypeBotApp;
}; };
} }
@ -11476,11 +11505,13 @@ namespace Api {
}; };
export class ChangeAuthorizationSettings extends Request<Partial<{ export class ChangeAuthorizationSettings extends Request<Partial<{
// flags: undefined; // flags: undefined;
confirmed?: true;
hash: long; hash: long;
encryptedRequestsDisabled?: Bool; encryptedRequestsDisabled?: Bool;
callRequestsDisabled?: Bool; callRequestsDisabled?: Bool;
}>, Bool> { }>, Bool> {
// flags: undefined; // flags: undefined;
confirmed?: true;
hash: long; hash: long;
encryptedRequestsDisabled?: Bool; encryptedRequestsDisabled?: Bool;
callRequestsDisabled?: Bool; callRequestsDisabled?: Bool;
@ -13409,15 +13440,19 @@ namespace Api {
export class RequestSimpleWebView extends Request<Partial<{ export class RequestSimpleWebView extends Request<Partial<{
// flags: undefined; // flags: undefined;
fromSwitchWebview?: true; fromSwitchWebview?: true;
fromSideMenu?: true;
bot: Api.TypeInputUser; bot: Api.TypeInputUser;
url: string; url?: string;
startParam?: string;
themeParams?: Api.TypeDataJSON; themeParams?: Api.TypeDataJSON;
platform: string; platform: string;
}>, Api.TypeSimpleWebViewResult> { }>, Api.TypeSimpleWebViewResult> {
// flags: undefined; // flags: undefined;
fromSwitchWebview?: true; fromSwitchWebview?: true;
fromSideMenu?: true;
bot: Api.TypeInputUser; bot: Api.TypeInputUser;
url: string; url?: string;
startParam?: string;
themeParams?: Api.TypeDataJSON; themeParams?: Api.TypeDataJSON;
platform: string; platform: string;
}; };

View File

@ -226,6 +226,7 @@ updateChatUserTyping#83487af0 chat_id:long from_id:Peer action:SendMessageAction
updateChatParticipants#7761198 participants:ChatParticipants = Update; updateChatParticipants#7761198 participants:ChatParticipants = Update;
updateUserStatus#e5bdf8de user_id:long status:UserStatus = Update; updateUserStatus#e5bdf8de user_id:long status:UserStatus = Update;
updateUserName#a7848924 user_id:long first_name:string last_name:string usernames:Vector<Username> = Update; updateUserName#a7848924 user_id:long first_name:string last_name:string usernames:Vector<Username> = Update;
updateNewAuthorization#8951abef flags:# unconfirmed:flags.0?true hash:long date:flags.0?int device:flags.0?string location:flags.0?string = Update;
updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update; updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update;
updateEncryptedChatTyping#1710f156 chat_id:int = Update; updateEncryptedChatTyping#1710f156 chat_id:int = Update;
updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update; updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update;
@ -240,7 +241,7 @@ updateUserPhone#5492a13 user_id:long phone:string = Update;
updateReadHistoryInbox#9c974fdf flags:# folder_id:flags.0?int peer:Peer max_id:int still_unread_count:int pts:int pts_count:int = Update; updateReadHistoryInbox#9c974fdf flags:# folder_id:flags.0?int peer:Peer max_id:int still_unread_count:int pts:int pts_count:int = Update;
updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update; updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update;
updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update; updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update;
updateReadMessagesContents#68c13933 messages:Vector<int> pts:int pts_count:int = Update; updateReadMessagesContents#f8227181 flags:# messages:Vector<int> pts:int pts_count:int date:flags.0?int = Update;
updateChannelTooLong#108d941f flags:# channel_id:long pts:flags.0?int = Update; updateChannelTooLong#108d941f flags:# channel_id:long pts:flags.0?int = Update;
updateChannel#635b4c09 channel_id:long = Update; updateChannel#635b4c09 channel_id:long = Update;
updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update; updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update;
@ -462,7 +463,7 @@ webPageEmpty#eb1477e8 id:long = WebPage;
webPagePending#c586da1c id:long date:int = WebPage; webPagePending#c586da1c id:long date:int = WebPage;
webPage#e89c45b2 flags:# id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page attributes:flags.12?Vector<WebPageAttribute> = WebPage; webPage#e89c45b2 flags:# id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page attributes:flags.12?Vector<WebPageAttribute> = WebPage;
webPageNotModified#7311ca11 flags:# cached_page_views:flags.0?int = WebPage; webPageNotModified#7311ca11 flags:# cached_page_views:flags.0?int = WebPage;
authorization#ad01d61d flags:# current:flags.0?true official_app:flags.1?true password_pending:flags.2?true encrypted_requests_disabled:flags.3?true call_requests_disabled:flags.4?true hash:long device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization; authorization#ad01d61d flags:# current:flags.0?true official_app:flags.1?true password_pending:flags.2?true encrypted_requests_disabled:flags.3?true call_requests_disabled:flags.4?true unconfirmed:flags.5?true hash:long device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization;
account.authorizations#4bff8ea0 authorization_ttl_days:int authorizations:Vector<Authorization> = account.Authorizations; account.authorizations#4bff8ea0 authorization_ttl_days:int authorizations:Vector<Authorization> = account.Authorizations;
account.password#957b50fb flags:# has_recovery:flags.0?true has_secure_values:flags.1?true has_password:flags.2?true current_algo:flags.2?PasswordKdfAlgo srp_B:flags.2?bytes srp_id:flags.2?long hint:flags.3?string email_unconfirmed_pattern:flags.4?string new_algo:PasswordKdfAlgo new_secure_algo:SecurePasswordKdfAlgo secure_random:bytes pending_reset_date:flags.5?int login_email_pattern:flags.6?string = account.Password; account.password#957b50fb flags:# has_recovery:flags.0?true has_secure_values:flags.1?true has_password:flags.2?true current_algo:flags.2?PasswordKdfAlgo srp_B:flags.2?bytes srp_id:flags.2?long hint:flags.3?string email_unconfirmed_pattern:flags.4?string new_algo:PasswordKdfAlgo new_secure_algo:SecurePasswordKdfAlgo secure_random:bytes pending_reset_date:flags.5?int login_email_pattern:flags.6?string = account.Password;
account.passwordSettings#9a5c33e5 flags:# email:flags.0?string secure_settings:flags.1?SecureSecretSettings = account.PasswordSettings; account.passwordSettings#9a5c33e5 flags:# email:flags.0?string secure_settings:flags.1?SecureSecretSettings = account.PasswordSettings;
@ -1027,7 +1028,7 @@ phone.groupCallStreamChannels#d0e482b2 channels:Vector<GroupCallStreamChannel> =
phone.groupCallStreamRtmpUrl#2dbf3432 url:string key:string = phone.GroupCallStreamRtmpUrl; phone.groupCallStreamRtmpUrl#2dbf3432 url:string key:string = phone.GroupCallStreamRtmpUrl;
attachMenuBotIconColor#4576f3f0 name:string color:int = AttachMenuBotIconColor; attachMenuBotIconColor#4576f3f0 name:string color:int = AttachMenuBotIconColor;
attachMenuBotIcon#b2a7386b flags:# name:string icon:Document colors:flags.0?Vector<AttachMenuBotIconColor> = AttachMenuBotIcon; attachMenuBotIcon#b2a7386b flags:# name:string icon:Document colors:flags.0?Vector<AttachMenuBotIconColor> = AttachMenuBotIcon;
attachMenuBot#c8aa2cd2 flags:# inactive:flags.0?true has_settings:flags.1?true request_write_access:flags.2?true bot_id:long short_name:string peer_types:Vector<AttachMenuPeerType> icons:Vector<AttachMenuBotIcon> = AttachMenuBot; attachMenuBot#d90d8dfe flags:# inactive:flags.0?true has_settings:flags.1?true request_write_access:flags.2?true show_in_attach_menu:flags.3?true show_in_side_menu:flags.4?true side_menu_disclaimer_needed:flags.5?true bot_id:long short_name:string peer_types:flags.3?Vector<AttachMenuPeerType> icons:Vector<AttachMenuBotIcon> = AttachMenuBot;
attachMenuBotsNotModified#f1d88a5c = AttachMenuBots; attachMenuBotsNotModified#f1d88a5c = AttachMenuBots;
attachMenuBots#3c4301c0 hash:long bots:Vector<AttachMenuBot> users:Vector<User> = AttachMenuBots; attachMenuBots#3c4301c0 hash:long bots:Vector<AttachMenuBot> users:Vector<User> = AttachMenuBots;
attachMenuBotsBot#93bf667f bot:AttachMenuBot users:Vector<User> = AttachMenuBotsBot; attachMenuBotsBot#93bf667f bot:AttachMenuBot users:Vector<User> = AttachMenuBotsBot;
@ -1110,7 +1111,7 @@ inputBotAppID#a920bd7a id:long access_hash:long = InputBotApp;
inputBotAppShortName#908c0407 bot_id:InputUser short_name:string = InputBotApp; inputBotAppShortName#908c0407 bot_id:InputUser short_name:string = InputBotApp;
botAppNotModified#5da674b7 = BotApp; botAppNotModified#5da674b7 = BotApp;
botApp#95fcd1d6 flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document hash:long = BotApp; botApp#95fcd1d6 flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document hash:long = BotApp;
messages.botApp#eb50adf5 flags:# inactive:flags.0?true request_write_access:flags.1?true app:BotApp = messages.BotApp; messages.botApp#eb50adf5 flags:# inactive:flags.0?true request_write_access:flags.1?true has_settings:flags.2?true app:BotApp = messages.BotApp;
appWebViewResultUrl#3c1b4f0d url:string = AppWebViewResult; appWebViewResultUrl#3c1b4f0d url:string = AppWebViewResult;
inlineBotWebView#b57295d5 text:string url:string = InlineBotWebView; inlineBotWebView#b57295d5 text:string url:string = InlineBotWebView;
readParticipantDate#4a4ff172 user_id:long date:int = ReadParticipantDate; readParticipantDate#4a4ff172 user_id:long date:int = ReadParticipantDate;
@ -1201,7 +1202,7 @@ account.getGlobalPrivacySettings#eb2b4cf6 = GlobalPrivacySettings;
account.setGlobalPrivacySettings#1edaaac2 settings:GlobalPrivacySettings = GlobalPrivacySettings; account.setGlobalPrivacySettings#1edaaac2 settings:GlobalPrivacySettings = GlobalPrivacySettings;
account.reportProfilePhoto#fa8cc6f5 peer:InputPeer photo_id:InputPhoto reason:ReportReason message:string = Bool; account.reportProfilePhoto#fa8cc6f5 peer:InputPeer photo_id:InputPhoto reason:ReportReason message:string = Bool;
account.setAuthorizationTTL#bf899aa0 authorization_ttl_days:int = Bool; account.setAuthorizationTTL#bf899aa0 authorization_ttl_days:int = Bool;
account.changeAuthorizationSettings#40f48462 flags:# hash:long encrypted_requests_disabled:flags.0?Bool call_requests_disabled:flags.1?Bool = Bool; account.changeAuthorizationSettings#40f48462 flags:# confirmed:flags.3?true hash:long encrypted_requests_disabled:flags.0?Bool call_requests_disabled:flags.1?Bool = Bool;
account.updateEmojiStatus#fbd3de6b emoji_status:EmojiStatus = Bool; account.updateEmojiStatus#fbd3de6b emoji_status:EmojiStatus = Bool;
account.getRecentEmojiStatuses#f578105 hash:long = account.EmojiStatuses; account.getRecentEmojiStatuses#f578105 hash:long = account.EmojiStatuses;
account.reorderUsernames#ef500eab order:Vector<string> = Bool; account.reorderUsernames#ef500eab order:Vector<string> = Bool;
@ -1331,7 +1332,7 @@ messages.getAttachMenuBot#77216192 bot:InputUser = AttachMenuBotsBot;
messages.toggleBotInAttachMenu#69f59d69 flags:# write_allowed:flags.0?true bot:InputUser enabled:Bool = Bool; messages.toggleBotInAttachMenu#69f59d69 flags:# write_allowed:flags.0?true bot:InputUser enabled:Bool = Bool;
messages.requestWebView#269dc2c1 flags:# from_bot_menu:flags.4?true silent:flags.5?true peer:InputPeer bot:InputUser url:flags.1?string start_param:flags.3?string theme_params:flags.2?DataJSON platform:string reply_to:flags.0?InputReplyTo send_as:flags.13?InputPeer = WebViewResult; messages.requestWebView#269dc2c1 flags:# from_bot_menu:flags.4?true silent:flags.5?true peer:InputPeer bot:InputUser url:flags.1?string start_param:flags.3?string theme_params:flags.2?DataJSON platform:string reply_to:flags.0?InputReplyTo send_as:flags.13?InputPeer = WebViewResult;
messages.prolongWebView#b0d81a83 flags:# silent:flags.5?true peer:InputPeer bot:InputUser query_id:long reply_to:flags.0?InputReplyTo send_as:flags.13?InputPeer = Bool; messages.prolongWebView#b0d81a83 flags:# silent:flags.5?true peer:InputPeer bot:InputUser query_id:long reply_to:flags.0?InputReplyTo send_as:flags.13?InputPeer = Bool;
messages.requestSimpleWebView#299bec8e flags:# from_switch_webview:flags.1?true bot:InputUser url:string theme_params:flags.0?DataJSON platform:string = SimpleWebViewResult; messages.requestSimpleWebView#1a46500a flags:# from_switch_webview:flags.1?true from_side_menu:flags.2?true bot:InputUser url:flags.3?string start_param:flags.4?string theme_params:flags.0?DataJSON platform:string = SimpleWebViewResult;
messages.sendWebViewResultMessage#a4314f5 bot_query_id:string result:InputBotInlineResult = WebViewMessageSent; messages.sendWebViewResultMessage#a4314f5 bot_query_id:string result:InputBotInlineResult = WebViewMessageSent;
messages.sendWebViewData#dc0242c8 bot:InputUser random_id:long button_text:string data:string = Updates; messages.sendWebViewData#dc0242c8 bot:InputUser random_id:long button_text:string data:string = Updates;
messages.transcribeAudio#269e9a49 peer:InputPeer msg_id:int = messages.TranscribedAudio; messages.transcribeAudio#269e9a49 peer:InputPeer msg_id:int = messages.TranscribedAudio;

View File

@ -279,6 +279,7 @@ updateChatUserTyping#83487af0 chat_id:long from_id:Peer action:SendMessageAction
updateChatParticipants#7761198 participants:ChatParticipants = Update; updateChatParticipants#7761198 participants:ChatParticipants = Update;
updateUserStatus#e5bdf8de user_id:long status:UserStatus = Update; updateUserStatus#e5bdf8de user_id:long status:UserStatus = Update;
updateUserName#a7848924 user_id:long first_name:string last_name:string usernames:Vector<Username> = Update; updateUserName#a7848924 user_id:long first_name:string last_name:string usernames:Vector<Username> = Update;
updateNewAuthorization#8951abef flags:# unconfirmed:flags.0?true hash:long date:flags.0?int device:flags.0?string location:flags.0?string = Update;
updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update; updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update;
updateEncryptedChatTyping#1710f156 chat_id:int = Update; updateEncryptedChatTyping#1710f156 chat_id:int = Update;
updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update; updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update;
@ -293,7 +294,7 @@ updateUserPhone#5492a13 user_id:long phone:string = Update;
updateReadHistoryInbox#9c974fdf flags:# folder_id:flags.0?int peer:Peer max_id:int still_unread_count:int pts:int pts_count:int = Update; updateReadHistoryInbox#9c974fdf flags:# folder_id:flags.0?int peer:Peer max_id:int still_unread_count:int pts:int pts_count:int = Update;
updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update; updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update;
updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update; updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update;
updateReadMessagesContents#68c13933 messages:Vector<int> pts:int pts_count:int = Update; updateReadMessagesContents#f8227181 flags:# messages:Vector<int> pts:int pts_count:int date:flags.0?int = Update;
updateChannelTooLong#108d941f flags:# channel_id:long pts:flags.0?int = Update; updateChannelTooLong#108d941f flags:# channel_id:long pts:flags.0?int = Update;
updateChannel#635b4c09 channel_id:long = Update; updateChannel#635b4c09 channel_id:long = Update;
updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update; updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update;
@ -552,7 +553,7 @@ webPagePending#c586da1c id:long date:int = WebPage;
webPage#e89c45b2 flags:# id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page attributes:flags.12?Vector<WebPageAttribute> = WebPage; webPage#e89c45b2 flags:# id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page attributes:flags.12?Vector<WebPageAttribute> = WebPage;
webPageNotModified#7311ca11 flags:# cached_page_views:flags.0?int = WebPage; webPageNotModified#7311ca11 flags:# cached_page_views:flags.0?int = WebPage;
authorization#ad01d61d flags:# current:flags.0?true official_app:flags.1?true password_pending:flags.2?true encrypted_requests_disabled:flags.3?true call_requests_disabled:flags.4?true hash:long device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization; authorization#ad01d61d flags:# current:flags.0?true official_app:flags.1?true password_pending:flags.2?true encrypted_requests_disabled:flags.3?true call_requests_disabled:flags.4?true unconfirmed:flags.5?true hash:long device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization;
account.authorizations#4bff8ea0 authorization_ttl_days:int authorizations:Vector<Authorization> = account.Authorizations; account.authorizations#4bff8ea0 authorization_ttl_days:int authorizations:Vector<Authorization> = account.Authorizations;
@ -1369,7 +1370,7 @@ attachMenuBotIconColor#4576f3f0 name:string color:int = AttachMenuBotIconColor;
attachMenuBotIcon#b2a7386b flags:# name:string icon:Document colors:flags.0?Vector<AttachMenuBotIconColor> = AttachMenuBotIcon; attachMenuBotIcon#b2a7386b flags:# name:string icon:Document colors:flags.0?Vector<AttachMenuBotIconColor> = AttachMenuBotIcon;
attachMenuBot#c8aa2cd2 flags:# inactive:flags.0?true has_settings:flags.1?true request_write_access:flags.2?true bot_id:long short_name:string peer_types:Vector<AttachMenuPeerType> icons:Vector<AttachMenuBotIcon> = AttachMenuBot; attachMenuBot#d90d8dfe flags:# inactive:flags.0?true has_settings:flags.1?true request_write_access:flags.2?true show_in_attach_menu:flags.3?true show_in_side_menu:flags.4?true side_menu_disclaimer_needed:flags.5?true bot_id:long short_name:string peer_types:flags.3?Vector<AttachMenuPeerType> icons:Vector<AttachMenuBotIcon> = AttachMenuBot;
attachMenuBotsNotModified#f1d88a5c = AttachMenuBots; attachMenuBotsNotModified#f1d88a5c = AttachMenuBots;
attachMenuBots#3c4301c0 hash:long bots:Vector<AttachMenuBot> users:Vector<User> = AttachMenuBots; attachMenuBots#3c4301c0 hash:long bots:Vector<AttachMenuBot> users:Vector<User> = AttachMenuBots;
@ -1499,7 +1500,7 @@ inputBotAppShortName#908c0407 bot_id:InputUser short_name:string = InputBotApp;
botAppNotModified#5da674b7 = BotApp; botAppNotModified#5da674b7 = BotApp;
botApp#95fcd1d6 flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document hash:long = BotApp; botApp#95fcd1d6 flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document hash:long = BotApp;
messages.botApp#eb50adf5 flags:# inactive:flags.0?true request_write_access:flags.1?true app:BotApp = messages.BotApp; messages.botApp#eb50adf5 flags:# inactive:flags.0?true request_write_access:flags.1?true has_settings:flags.2?true app:BotApp = messages.BotApp;
appWebViewResultUrl#3c1b4f0d url:string = AppWebViewResult; appWebViewResultUrl#3c1b4f0d url:string = AppWebViewResult;
@ -1667,7 +1668,7 @@ account.resetPassword#9308ce1b = account.ResetPasswordResult;
account.declinePasswordReset#4c9409f6 = Bool; account.declinePasswordReset#4c9409f6 = Bool;
account.getChatThemes#d638de89 hash:long = account.Themes; account.getChatThemes#d638de89 hash:long = account.Themes;
account.setAuthorizationTTL#bf899aa0 authorization_ttl_days:int = Bool; account.setAuthorizationTTL#bf899aa0 authorization_ttl_days:int = Bool;
account.changeAuthorizationSettings#40f48462 flags:# hash:long encrypted_requests_disabled:flags.0?Bool call_requests_disabled:flags.1?Bool = Bool; account.changeAuthorizationSettings#40f48462 flags:# confirmed:flags.3?true hash:long encrypted_requests_disabled:flags.0?Bool call_requests_disabled:flags.1?Bool = Bool;
account.getSavedRingtones#e1902288 hash:long = account.SavedRingtones; account.getSavedRingtones#e1902288 hash:long = account.SavedRingtones;
account.saveRingtone#3dea5b03 id:InputDocument unsave:Bool = account.SavedRingtone; account.saveRingtone#3dea5b03 id:InputDocument unsave:Bool = account.SavedRingtone;
account.uploadRingtone#831a83a2 file:InputFile file_name:string mime_type:string = Document; account.uploadRingtone#831a83a2 file:InputFile file_name:string mime_type:string = Document;
@ -1879,7 +1880,7 @@ messages.getAttachMenuBot#77216192 bot:InputUser = AttachMenuBotsBot;
messages.toggleBotInAttachMenu#69f59d69 flags:# write_allowed:flags.0?true bot:InputUser enabled:Bool = Bool; messages.toggleBotInAttachMenu#69f59d69 flags:# write_allowed:flags.0?true bot:InputUser enabled:Bool = Bool;
messages.requestWebView#269dc2c1 flags:# from_bot_menu:flags.4?true silent:flags.5?true peer:InputPeer bot:InputUser url:flags.1?string start_param:flags.3?string theme_params:flags.2?DataJSON platform:string reply_to:flags.0?InputReplyTo send_as:flags.13?InputPeer = WebViewResult; messages.requestWebView#269dc2c1 flags:# from_bot_menu:flags.4?true silent:flags.5?true peer:InputPeer bot:InputUser url:flags.1?string start_param:flags.3?string theme_params:flags.2?DataJSON platform:string reply_to:flags.0?InputReplyTo send_as:flags.13?InputPeer = WebViewResult;
messages.prolongWebView#b0d81a83 flags:# silent:flags.5?true peer:InputPeer bot:InputUser query_id:long reply_to:flags.0?InputReplyTo send_as:flags.13?InputPeer = Bool; messages.prolongWebView#b0d81a83 flags:# silent:flags.5?true peer:InputPeer bot:InputUser query_id:long reply_to:flags.0?InputReplyTo send_as:flags.13?InputPeer = Bool;
messages.requestSimpleWebView#299bec8e flags:# from_switch_webview:flags.1?true bot:InputUser url:string theme_params:flags.0?DataJSON platform:string = SimpleWebViewResult; messages.requestSimpleWebView#1a46500a flags:# from_switch_webview:flags.1?true from_side_menu:flags.2?true bot:InputUser url:flags.3?string start_param:flags.4?string theme_params:flags.0?DataJSON platform:string = SimpleWebViewResult;
messages.sendWebViewResultMessage#a4314f5 bot_query_id:string result:InputBotInlineResult = WebViewMessageSent; messages.sendWebViewResultMessage#a4314f5 bot_query_id:string result:InputBotInlineResult = WebViewMessageSent;
messages.sendWebViewData#dc0242c8 bot:InputUser random_id:long button_text:string data:string = Updates; messages.sendWebViewData#dc0242c8 bot:InputUser random_id:long button_text:string data:string = Updates;
messages.transcribeAudio#269e9a49 peer:InputPeer msg_id:int = messages.TranscribedAudio; messages.transcribeAudio#269e9a49 peer:InputPeer msg_id:int = messages.TranscribedAudio;

View File

@ -59,7 +59,8 @@ export type WebAppInboundEvent = {
} | { } | {
eventType: 'web_app_set_header_color'; eventType: 'web_app_set_header_color';
eventData: { eventData: {
color_key: 'bg_color' | 'secondary_bg_color'; color_key?: 'bg_color' | 'secondary_bg_color';
color?: string;
}; };
} | { } | {
eventType: 'web_app_open_popup'; eventType: 'web_app_open_popup';