Title: Display current chat in page title (#2564)

This commit is contained in:
Alexander Zinchuk 2023-02-13 03:32:35 +01:00
parent 5f4ca63148
commit ec1895b5d1
10 changed files with 95 additions and 44 deletions

View File

@ -11,7 +11,6 @@ src/lib/lovely-chart
src/lib/music-metadata-browser src/lib/music-metadata-browser
webpack.config.js
jest.config.js jest.config.js
src/lib/secret-sauce/ src/lib/secret-sauce/
playwright.config.ts playwright.config.ts

View File

@ -5,8 +5,8 @@ import { getActions, withGlobal } from './global';
import type { GlobalState } from './global/types'; import type { GlobalState } from './global/types';
import type { UiLoaderPage } from './components/common/UiLoader'; import type { UiLoaderPage } from './components/common/UiLoader';
import { INACTIVE_MARKER, PAGE_TITLE } from './config';
import { IS_MULTITAB_SUPPORTED, PLATFORM_ENV } from './util/environment'; import { IS_MULTITAB_SUPPORTED, PLATFORM_ENV } from './util/environment';
import { INACTIVE_MARKER, PAGE_TITLE } from './config';
import { selectTabState } from './global/selectors'; import { selectTabState } from './global/selectors';
import { updateSizes } from './util/windowSize'; import { updateSizes } from './util/windowSize';
import { addActiveTabChangeListener } from './util/activeTabMonitor'; import { addActiveTabChangeListener } from './util/activeTabMonitor';
@ -40,6 +40,8 @@ enum AppScreens {
inactive, inactive,
} }
const INACTIVE_PAGE_TITLE = `${PAGE_TITLE} ${INACTIVE_MARKER}`;
const App: FC<StateProps> = ({ const App: FC<StateProps> = ({
authState, authState,
isScreenLocked, isScreenLocked,
@ -47,7 +49,7 @@ const App: FC<StateProps> = ({
hasWebAuthTokenFailed, hasWebAuthTokenFailed,
isInactiveAuth, isInactiveAuth,
}) => { }) => {
const { disconnect } = getActions(); const { disconnect, updatePageTitle } = getActions();
const [isInactive, markInactive, unmarkInactive] = useFlag(false); const [isInactive, markInactive, unmarkInactive] = useFlag(false);
const { isMobile } = useAppLayout(); const { isMobile } = useAppLayout();
@ -144,20 +146,20 @@ const App: FC<StateProps> = ({
addActiveTabChangeListener(() => { addActiveTabChangeListener(() => {
disconnect(); disconnect();
document.title = `${PAGE_TITLE}${INACTIVE_MARKER}`; document.title = INACTIVE_PAGE_TITLE;
markInactive(); markInactive();
}); });
}, [activeKey, disconnect, markInactive]); }, [activeKey, disconnect, markInactive, updatePageTitle]);
useEffect(() => { useEffect(() => {
if (isInactiveAuth) { if (isInactiveAuth) {
document.title = `${PAGE_TITLE}${INACTIVE_MARKER}`; document.title = INACTIVE_PAGE_TITLE;
markInactive(); markInactive();
} else { } else {
unmarkInactive(); unmarkInactive();
} }
}, [isInactiveAuth, markInactive, unmarkInactive]); }, [isInactiveAuth, markInactive, unmarkInactive, updatePageTitle]);
const prevActiveKey = usePrevious(activeKey); const prevActiveKey = usePrevious(activeKey);

View File

@ -13,7 +13,7 @@ import type { ApiLimitTypeWithModal, TabState } from '../../global/types';
import '../../global/actions/all'; import '../../global/actions/all';
import { import {
BASE_EMOJI_KEYWORD_LANG, DEBUG, INACTIVE_MARKER, PAGE_TITLE, BASE_EMOJI_KEYWORD_LANG, DEBUG, INACTIVE_MARKER,
} from '../../config'; } from '../../config';
import { IS_ANDROID } from '../../util/environment'; import { IS_ANDROID } from '../../util/environment';
import { import {
@ -43,7 +43,6 @@ import useShowTransition from '../../hooks/useShowTransition';
import { dispatchHeavyAnimationEvent } from '../../hooks/useHeavyAnimationCheck'; import { dispatchHeavyAnimationEvent } from '../../hooks/useHeavyAnimationCheck';
import useInterval from '../../hooks/useInterval'; import useInterval from '../../hooks/useInterval';
import useAppLayout from '../../hooks/useAppLayout'; import useAppLayout from '../../hooks/useAppLayout';
import updatePageTitle from '../../util/updatePageTitle';
import updateIcon from '../../util/updateIcon'; import updateIcon from '../../util/updateIcon';
import StickerSetModal from '../common/StickerSetModal.async'; import StickerSetModal from '../common/StickerSetModal.async';
@ -214,6 +213,7 @@ const Main: FC<OwnProps & StateProps> = ({
openChat, openChat,
toggleLeftColumn, toggleLeftColumn,
loadRecentEmojiStatuses, loadRecentEmojiStatuses,
updatePageTitle,
} = getActions(); } = getActions();
if (DEBUG && !DEBUG_isLogged) { if (DEBUG && !DEBUG_isLogged) {
@ -415,11 +415,11 @@ const Main: FC<OwnProps & StateProps> = ({
onTabFocusChange({ isBlurred: false }); onTabFocusChange({ isBlurred: false });
if (!document.title.includes(INACTIVE_MARKER)) { if (!document.title.includes(INACTIVE_MARKER)) {
updatePageTitle(PAGE_TITLE); updatePageTitle();
} }
updateIcon(false); updateIcon(false);
}, [onTabFocusChange]); }, [onTabFocusChange, updatePageTitle]);
const handleStickerSetModalClose = useCallback(() => { const handleStickerSetModalClose = useCallback(() => {
closeStickerSetModal(); closeStickerSetModal();

View File

@ -19,8 +19,8 @@ export const BETA_CHANGELOG_URL = 'https://telegra.ph/WebZ-Beta-04-01';
export const DEBUG_ALERT_MSG = 'Shoot!\nSomething went wrong, please see the error details in Dev Tools Console.'; export const DEBUG_ALERT_MSG = 'Shoot!\nSomething went wrong, please see the error details in Dev Tools Console.';
export const DEBUG_GRAMJS = false; export const DEBUG_GRAMJS = false;
export const PAGE_TITLE = 'Telegram'; export const PAGE_TITLE = process.env.APP_TITLE!;
export const INACTIVE_MARKER = ' [Inactive]'; export const INACTIVE_MARKER = '[Inactive]';
export const DEBUG_PAYMENT_SMART_GLOCAL = false; export const DEBUG_PAYMENT_SMART_GLOCAL = false;

View File

@ -66,6 +66,8 @@ addActionHandler('openChat', (global, actions, payload): ActionReturnType => {
} }
} }
actions.updatePageTitle({ tabId });
return updateCurrentMessageList(global, id, threadId, type, shouldReplaceHistory, tabId); return updateCurrentMessageList(global, id, threadId, type, shouldReplaceHistory, tabId);
}); });

View File

@ -1,24 +1,26 @@
import { addActionHandler, getGlobal, setGlobal } from '../../index'; import { addCallback } from '../../../lib/teact/teactn';
import {
addActionHandler, getActions, getGlobal, setGlobal,
} from '../../index';
import type { ApiError, ApiNotification } from '../../../api/types'; import type { ApiError, ApiNotification } from '../../../api/types';
import { MAIN_THREAD_ID } from '../../../api/types'; import { MAIN_THREAD_ID } from '../../../api/types';
import type { ActionReturnType, GlobalState } from '../../types';
import { import {
APP_VERSION, DEBUG, GLOBAL_STATE_CACHE_CUSTOM_EMOJI_LIMIT, INACTIVE_MARKER, PAGE_TITLE, APP_VERSION, DEBUG, GLOBAL_STATE_CACHE_CUSTOM_EMOJI_LIMIT, INACTIVE_MARKER, PAGE_TITLE,
} from '../../../config'; } from '../../../config';
import getReadableErrorText from '../../../util/getReadableErrorText'; import getReadableErrorText from '../../../util/getReadableErrorText';
import { import {
selectChatMessage, selectCurrentChat, selectCurrentMessageList, selectTabState, selectIsTrustedBot, selectChatMessage, selectCurrentChat, selectCurrentMessageList, selectTabState, selectIsTrustedBot, selectChat,
} from '../../selectors'; } from '../../selectors';
import generateIdFor from '../../../util/generateIdFor'; import generateIdFor from '../../../util/generateIdFor';
import { unique } from '../../../util/iteratees'; import { unique } from '../../../util/iteratees';
import { getAllMultitabTokens, getCurrentTabId, reestablishMasterToSelf } from '../../../util/establishMultitabRole'; import { getAllMultitabTokens, getCurrentTabId, reestablishMasterToSelf } from '../../../util/establishMultitabRole';
import { getAllNotificationsCount } from '../../../util/folderManager'; import { getAllNotificationsCount } from '../../../util/folderManager';
import updateIcon from '../../../util/updateIcon'; import updateIcon from '../../../util/updateIcon';
import updatePageTitle from '../../../util/updatePageTitle'; import setPageTitle from '../../../util/updatePageTitle';
import type { ActionReturnType, GlobalState } from '../../types';
import { updateTabState } from '../../reducers/tabs'; import { updateTabState } from '../../reducers/tabs';
import { addCallback } from '../../../lib/teact/teactn';
import { getIsMobile, getIsTablet } from '../../../hooks/useAppLayout'; import { getIsMobile, getIsTablet } from '../../../hooks/useAppLayout';
export const APP_VERSION_URL = 'version.txt'; export const APP_VERSION_URL = 'version.txt';
@ -601,29 +603,61 @@ addActionHandler('onTabFocusChange', (global, actions, payload): ActionReturnTyp
}; };
}); });
addActionHandler('updatePageTitle', (global, actions, payload): ActionReturnType => {
const { isInactive, notificationCount, tabId = getCurrentTabId() } = payload || {};
if (isInactive) {
setPageTitle(`${PAGE_TITLE} ${INACTIVE_MARKER}`);
return;
}
if (notificationCount) {
setPageTitle(`${notificationCount} notification${notificationCount > 1 ? 's' : ''}`);
return;
}
const messageList = selectCurrentMessageList(global, tabId);
if (messageList) {
const { chatId, threadId } = messageList;
const currentChat = selectChat(global, chatId);
if (currentChat) {
if (currentChat.isForum && currentChat.topics?.[threadId]) {
setPageTitle(`${currentChat.title} ${currentChat.topics[threadId].title}`);
return;
}
setPageTitle(currentChat.title);
return;
}
}
setPageTitle(PAGE_TITLE);
});
addCallback((global: GlobalState) => { addCallback((global: GlobalState) => {
if (global.notificationIndex === undefined || global.allNotificationsCount === undefined) return; if (global.notificationIndex === undefined || global.allNotificationsCount === undefined) return;
const { updatePageTitle } = getActions();
const index = global.notificationIndex; const index = global.notificationIndex;
const allNotificationsCount = global.allNotificationsCount; const allNotificationsCount = global.allNotificationsCount;
if (document.title.includes(INACTIVE_MARKER) || !global.initialUnreadNotifications) { if (document.title.includes(INACTIVE_MARKER) || !global.initialUnreadNotifications) {
updateIcon(false); updateIcon(false);
updatePageTitle(PAGE_TITLE); updatePageTitle();
return; return;
} }
if (index % 2 === 0) { if (index % 2 === 0) {
const newUnread = allNotificationsCount - global.initialUnreadNotifications; const newUnread = allNotificationsCount - global.initialUnreadNotifications;
if (newUnread > 0) { if (newUnread > 0) {
updatePageTitle(`${newUnread} notification${newUnread > 1 ? 's' : ''}`); updatePageTitle({
notificationCount: newUnread,
});
updateIcon(true); updateIcon(true);
} else { return;
updatePageTitle(PAGE_TITLE);
updateIcon(false);
} }
} else {
updatePageTitle(PAGE_TITLE);
updateIcon(false);
} }
updatePageTitle();
updateIcon(false);
}); });

View File

@ -2098,6 +2098,11 @@ export interface ActionPayloads {
} & WithTabId; } & WithTabId;
dismissNotification: { localId: string } & WithTabId; dismissNotification: { localId: string } & WithTabId;
updatePageTitle: {
isInactive?: boolean;
notificationCount?: number;
} & WithTabId | undefined;
// Calls // Calls
joinGroupCall: { joinGroupCall: {
chatId?: string; chatId?: string;

View File

@ -4,16 +4,16 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title><%= htmlWebpackPlugin.options.appName %></title> <title><%= htmlWebpackPlugin.options.appTitle %></title>
<meta name="title" content="<%= htmlWebpackPlugin.options.appName %>"> <meta name="title" content="<%= htmlWebpackPlugin.options.appTitle %>">
<meta name="description" content="Telegram is a cloud-based mobile and desktop messaging app with a focus on security and speed."> <meta name="description" content="Telegram is a cloud-based mobile and desktop messaging app with a focus on security and speed.">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no, shrink-to-fit=no, viewport-fit=cover"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no, shrink-to-fit=no, viewport-fit=cover">
<meta name="mobile-web-app-capable" content="yes"> <meta name="mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-title" content="<%= htmlWebpackPlugin.options.appName %>"> <meta name="mobile-web-app-title" content="<%= htmlWebpackPlugin.options.appTitle %>">
<meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-title" content="<%= htmlWebpackPlugin.options.appName %>"> <meta name="apple-mobile-web-app-title" content="<%= htmlWebpackPlugin.options.appTitle %>">
<meta name="application-name" content="<%= htmlWebpackPlugin.options.appName %>"> <meta name="application-name" content="<%= htmlWebpackPlugin.options.appTitle %>">
<meta name="msapplication-TileColor" content="#2b5797"> <meta name="msapplication-TileColor" content="#2b5797">
<meta name="msapplication-config" content="./browserconfig.xml"> <meta name="msapplication-config" content="./browserconfig.xml">
<meta name="theme-color" content="#ffffff"> <meta name="theme-color" content="#ffffff">
@ -22,14 +22,14 @@
<!-- Open Graph / Facebook --> <!-- Open Graph / Facebook -->
<meta property="og:type" content="website"> <meta property="og:type" content="website">
<meta property="og:url" content="<%= htmlWebpackPlugin.options.baseUrl %>"> <meta property="og:url" content="<%= htmlWebpackPlugin.options.baseUrl %>">
<meta property="og:title" content="<%= htmlWebpackPlugin.options.appName %>"> <meta property="og:title" content="<%= htmlWebpackPlugin.options.appTitle %>">
<meta property="og:description" content="Telegram is a cloud-based mobile and desktop messaging app with a focus on security and speed."> <meta property="og:description" content="Telegram is a cloud-based mobile and desktop messaging app with a focus on security and speed.">
<meta property="og:image" content="./<%= htmlWebpackPlugin.options.mainIcon %>.png"> <meta property="og:image" content="./<%= htmlWebpackPlugin.options.mainIcon %>.png">
<!-- Twitter --> <!-- Twitter -->
<meta property="twitter:card" content="summary_large_image"> <meta property="twitter:card" content="summary_large_image">
<meta property="twitter:url" content="<%= htmlWebpackPlugin.options.baseUrl %>"> <meta property="twitter:url" content="<%= htmlWebpackPlugin.options.baseUrl %>">
<meta property="twitter:title" content="<%= htmlWebpackPlugin.options.appName %>"> <meta property="twitter:title" content="<%= htmlWebpackPlugin.options.appTitle %>">
<meta property="twitter:description" content="Telegram is a cloud-based mobile and desktop messaging app with a focus on security and speed."> <meta property="twitter:description" content="Telegram is a cloud-based mobile and desktop messaging app with a focus on security and speed.">
<meta property="twitter:image" content="./<%= htmlWebpackPlugin.options.mainIcon %>.png"> <meta property="twitter:image" content="./<%= htmlWebpackPlugin.options.mainIcon %>.png">

View File

@ -26,5 +26,6 @@
"tests", "tests",
"plugins", "plugins",
"dev", "dev",
"webpack.config.js",
] ]
} }

View File

@ -23,7 +23,12 @@ const {
dotenv.config(); dotenv.config();
const { BASE_URL = 'https://web.telegram.org/z/' } = process.env; const DEFAULT_APP_TITLE = `Telegram${APP_ENV !== 'production' ? ' Beta' : ''}`;
const {
BASE_URL = 'https://web.telegram.org/z/',
APP_TITLE = DEFAULT_APP_TITLE,
} = process.env;
module.exports = (_env, { mode = 'production' }) => { module.exports = (_env, { mode = 'production' }) => {
return { return {
@ -34,7 +39,7 @@ module.exports = (_env, { mode = 'production' }) => {
devServer: { devServer: {
port: 1234, port: 1234,
host: '0.0.0.0', host: '0.0.0.0',
allowedHosts: "all", allowedHosts: 'all',
hot: false, hot: false,
static: [ static: [
{ {
@ -99,9 +104,9 @@ module.exports = (_env, { mode = 'production' }) => {
modules: { modules: {
exportLocalsConvention: 'camelCase', exportLocalsConvention: 'camelCase',
auto: true, auto: true,
localIdentName: mode === 'production' ? '[hash:base64]' : '[name]__[local]' localIdentName: mode === 'production' ? '[hash:base64]' : '[name]__[local]',
} },
} },
}, },
'postcss-loader', 'postcss-loader',
'sass-loader', 'sass-loader',
@ -136,15 +141,15 @@ module.exports = (_env, { mode = 'production' }) => {
plugins: [ plugins: [
// Clearing of the unused files for code highlight for smaller chunk count // Clearing of the unused files for code highlight for smaller chunk count
new ContextReplacementPlugin( new ContextReplacementPlugin(
/highlight\.js[\\\/]lib[\\\/]languages/, /highlight\.js[\\/]lib[\\/]languages/,
/^((?!\.js\.js).)*$/ /^((?!\.js\.js).)*$/,
), ),
...(APP_MOCKED_CLIENT === '1' ? [new NormalModuleReplacementPlugin( ...(APP_MOCKED_CLIENT === '1' ? [new NormalModuleReplacementPlugin(
/src[\\\/]lib[\\\/]gramjs[\\\/]client[\\\/]TelegramClient\.js/, /src[\\/]lib[\\/]gramjs[\\/]client[\\/]TelegramClient\.js/,
'./MockClient.ts' './MockClient.ts',
)] : []), )] : []),
new HtmlWebpackPlugin({ new HtmlWebpackPlugin({
appName: APP_ENV === 'production' ? 'Telegram Web' : 'Telegram Web Beta', appTitle: APP_TITLE,
appleIcon: APP_ENV === 'production' ? 'apple-touch-icon' : 'apple-touch-icon-dev', appleIcon: APP_ENV === 'production' ? 'apple-touch-icon' : 'apple-touch-icon-dev',
mainIcon: APP_ENV === 'production' ? 'icon-192x192' : 'icon-dev-192x192', mainIcon: APP_ENV === 'production' ? 'icon-192x192' : 'icon-dev-192x192',
manifest: APP_ENV === 'production' ? 'site.webmanifest' : 'site_dev.webmanifest', manifest: APP_ENV === 'production' ? 'site.webmanifest' : 'site_dev.webmanifest',
@ -159,11 +164,14 @@ module.exports = (_env, { mode = 'production' }) => {
new EnvironmentPlugin({ new EnvironmentPlugin({
APP_ENV, APP_ENV,
APP_MOCKED_CLIENT, APP_MOCKED_CLIENT,
// eslint-disable-next-line no-null/no-null
APP_NAME: null, APP_NAME: null,
APP_VERSION: appVersion, APP_VERSION: appVersion,
APP_TITLE,
RELEASE_DATETIME: Date.now(), RELEASE_DATETIME: Date.now(),
TELEGRAM_T_API_ID: undefined, TELEGRAM_T_API_ID: undefined,
TELEGRAM_T_API_HASH: undefined, TELEGRAM_T_API_HASH: undefined,
// eslint-disable-next-line no-null/no-null
TEST_SESSION: null, TEST_SESSION: null,
}), }),
new DefinePlugin({ new DefinePlugin({
@ -193,7 +201,7 @@ module.exports = (_env, { mode = 'production' }) => {
...(APP_ENV !== 'production' && { ...(APP_ENV !== 'production' && {
optimization: { optimization: {
chunkIds: 'named', chunkIds: 'named',
} },
}), }),
}; };
}; };