Compare versions for "Update Telegram" button; Various UI fixes (#2022)

This commit is contained in:
Alexander Zinchuk 2022-09-12 11:05:53 +02:00
parent bf4812f6cf
commit 6d0c4e4b66
12 changed files with 79 additions and 57 deletions

View File

@ -4,14 +4,15 @@
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"dev": "cross-env APP_ENV=development webpack serve --mode development", "dev": "cross-env APP_ENV=development APP_VERSION=$(npm run print_version --silent) webpack serve --mode development",
"dev:mocked": "cross-env APP_ENV=test APP_MOCKED_CLIENT=1 webpack serve --mode development --port 1235", "dev:mocked": "cross-env APP_ENV=test APP_MOCKED_CLIENT=1 webpack serve --mode development --port 1235",
"build:mocked": "cross-env APP_ENV=test APP_MOCKED_CLIENT=1 webpack --mode development", "build:mocked": "cross-env APP_ENV=test APP_MOCKED_CLIENT=1 webpack --mode development",
"build:staging": "APP_ENV=staging APP_VERSION=$(npm run print_version --silent) webpack --mode development && ./deploy/copy_to_dist.sh", "build:staging": "APP_ENV=staging APP_VERSION=$(npm run print_version --silent) webpack --mode development && ./deploy/copy_to_dist.sh",
"build:production": "npm i && APP_VERSION=$(npm run inc_version --silent) webpack && ./deploy/copy_to_dist.sh", "build:production": "npm i && APP_VERSION=$(npm run inc_version --silent) webpack && ./deploy/copy_to_dist.sh",
"deploy:production": "npm run build:production && git add -A && git commit -a -m '[Build]' --no-verify && git push", "deploy:production": "npm run build:production && git add -A && git commit -a -m '[Build]' --no-verify && git push",
"print_version": "node -p -e \"require('./package.json').version\"", "update_version": "npm run print_version --silent > ./public/version.txt",
"inc_version": "echo $((`cat .patch-version` + 1)) > .patch-version && echo \"$(node -p -e \"require('./package.json').version.match(/^\\d+\\.\\d+/)[0]\").$(cat .patch-version)\"", "print_version": "echo \"$(node -p -e \"require('./package.json').version.match(/^\\d+\\.\\d+/)[0]\").$(cat .patch-version)\"",
"inc_version": "echo $((`cat .patch-version` + 1)) > .patch-version && npm run update_version --silent && npm run print_version",
"telegraph:update_changelog": "node ./dev/telegraphChangelog.js", "telegraph:update_changelog": "node ./dev/telegraphChangelog.js",
"check": "tsc && stylelint \"**/*.{css,scss}\" && eslint . --ext .ts,.tsx,.js --ignore-pattern src/lib/gramjs", "check": "tsc && stylelint \"**/*.{css,scss}\" && eslint . --ext .ts,.tsx,.js --ignore-pattern src/lib/gramjs",
"check:fix": "npm run check -- --fix", "check:fix": "npm run check -- --fix",

1
public/version.txt Normal file
View File

@ -0,0 +1 @@
1.51.1

View File

@ -32,6 +32,7 @@ type StateProps = {
hasPasscode?: boolean; hasPasscode?: boolean;
nextSettingsScreen?: SettingsScreens; nextSettingsScreen?: SettingsScreens;
isChatOpen: boolean; isChatOpen: boolean;
isUpdateAvailable?: boolean;
}; };
enum ContentType { enum ContentType {
@ -58,6 +59,7 @@ const LeftColumn: FC<StateProps> = ({
hasPasscode, hasPasscode,
nextSettingsScreen, nextSettingsScreen,
isChatOpen, isChatOpen,
isUpdateAvailable,
}) => { }) => {
const { const {
setGlobalSearchQuery, setGlobalSearchQuery,
@ -440,6 +442,7 @@ const LeftColumn: FC<StateProps> = ({
onScreenSelect={handleSettingsScreenSelect} onScreenSelect={handleSettingsScreenSelect}
onReset={handleReset} onReset={handleReset}
shouldSkipTransition={shouldSkipHistoryAnimations} shouldSkipTransition={shouldSkipHistoryAnimations}
isUpdateAvailable={isUpdateAvailable}
/> />
); );
} }
@ -474,6 +477,7 @@ export default memo(withGlobal(
settings: { settings: {
nextScreen: nextSettingsScreen, nextScreen: nextSettingsScreen,
}, },
isUpdateAvailable,
} = global; } = global;
const isChatOpen = Boolean(selectCurrentChat(global)?.id); const isChatOpen = Boolean(selectCurrentChat(global)?.id);
@ -488,6 +492,7 @@ export default memo(withGlobal(
hasPasscode, hasPasscode,
nextSettingsScreen, nextSettingsScreen,
isChatOpen, isChatOpen,
isUpdateAvailable,
}; };
}, },
)(LeftColumn)); )(LeftColumn));

View File

@ -43,6 +43,7 @@
> span { > span {
padding-left: 0.5rem; padding-left: 0.5rem;
padding-right: 0.5rem; padding-right: 0.5rem;
white-space: pre;
} }
} }

View File

@ -9,7 +9,6 @@ import type { FolderEditDispatch } from '../../../hooks/reducers/useFoldersReduc
import { IS_TOUCH_ENV } from '../../../util/environment'; import { IS_TOUCH_ENV } from '../../../util/environment';
import buildClassName from '../../../util/buildClassName'; import buildClassName from '../../../util/buildClassName';
import useFlag from '../../../hooks/useFlag';
import useShowTransition from '../../../hooks/useShowTransition'; import useShowTransition from '../../../hooks/useShowTransition';
import useLang from '../../../hooks/useLang'; import useLang from '../../../hooks/useLang';
@ -30,6 +29,7 @@ type OwnProps = {
contactsFilter: string; contactsFilter: string;
shouldSkipTransition?: boolean; shouldSkipTransition?: boolean;
foldersDispatch: FolderEditDispatch; foldersDispatch: FolderEditDispatch;
isUpdateAvailable?: boolean;
onSearchQuery: (query: string) => void; onSearchQuery: (query: string) => void;
onContentChange: (content: LeftColumnContent) => void; onContentChange: (content: LeftColumnContent) => void;
onScreenSelect: (screen: SettingsScreens) => void; onScreenSelect: (screen: SettingsScreens) => void;
@ -38,7 +38,6 @@ type OwnProps = {
const TRANSITION_RENDER_COUNT = Object.keys(LeftColumnContent).length / 2; const TRANSITION_RENDER_COUNT = Object.keys(LeftColumnContent).length / 2;
const BUTTON_CLOSE_DELAY_MS = 250; const BUTTON_CLOSE_DELAY_MS = 250;
const APP_OUTDATED_TIMEOUT = 3 * 24 * 60 * 60 * 1000; // 3 days
let closeTimeout: number | undefined; let closeTimeout: number | undefined;
@ -49,6 +48,7 @@ const LeftMain: FC<OwnProps> = ({
contactsFilter, contactsFilter,
shouldSkipTransition, shouldSkipTransition,
foldersDispatch, foldersDispatch,
isUpdateAvailable,
onSearchQuery, onSearchQuery,
onContentChange, onContentChange,
onScreenSelect, onScreenSelect,
@ -56,28 +56,13 @@ const LeftMain: FC<OwnProps> = ({
}) => { }) => {
const [isNewChatButtonShown, setIsNewChatButtonShown] = useState(IS_TOUCH_ENV); const [isNewChatButtonShown, setIsNewChatButtonShown] = useState(IS_TOUCH_ENV);
const {
shouldRender: shouldRenderUpdateButton,
transitionClassNames: updateButtonClassNames,
} = useShowTransition(isUpdateAvailable);
const isMouseInside = useRef(false); const isMouseInside = useRef(false);
const handleSelectSettings = useCallback(() => {
onContentChange(LeftColumnContent.Settings);
}, [onContentChange]);
const handleSelectContacts = useCallback(() => {
onContentChange(LeftColumnContent.Contacts);
}, [onContentChange]);
const handleSelectNewChannel = useCallback(() => {
onContentChange(LeftColumnContent.NewChannelStep1);
}, [onContentChange]);
const handleSelectNewGroup = useCallback(() => {
onContentChange(LeftColumnContent.NewGroupStep1);
}, [onContentChange]);
const handleSelectArchived = useCallback(() => {
onContentChange(LeftColumnContent.Archived);
}, [onContentChange]);
const handleMouseEnter = useCallback(() => { const handleMouseEnter = useCallback(() => {
if (content !== LeftColumnContent.ChatList) { if (content !== LeftColumnContent.ChatList) {
return; return;
@ -101,6 +86,30 @@ const LeftMain: FC<OwnProps> = ({
}, BUTTON_CLOSE_DELAY_MS); }, BUTTON_CLOSE_DELAY_MS);
}, []); }, []);
const handleSelectSettings = useCallback(() => {
onContentChange(LeftColumnContent.Settings);
}, [onContentChange]);
const handleSelectContacts = useCallback(() => {
onContentChange(LeftColumnContent.Contacts);
}, [onContentChange]);
const handleSelectArchived = useCallback(() => {
onContentChange(LeftColumnContent.Archived);
}, [onContentChange]);
const handleUpdateClick = useCallback(() => {
window.location.reload();
}, []);
const handleSelectNewChannel = useCallback(() => {
onContentChange(LeftColumnContent.NewChannelStep1);
}, [onContentChange]);
const handleSelectNewGroup = useCallback(() => {
onContentChange(LeftColumnContent.NewGroupStep1);
}, [onContentChange]);
useEffect(() => { useEffect(() => {
let autoCloseTimeout: number | undefined; let autoCloseTimeout: number | undefined;
if (content !== LeftColumnContent.ChatList) { if (content !== LeftColumnContent.ChatList) {
@ -119,8 +128,6 @@ const LeftMain: FC<OwnProps> = ({
}; };
}, [content]); }, [content]);
const [shouldRenderUpdateButton, updateButtonClassNames, handleUpdateClick] = useAppOutdatedCheck();
const lang = useLang(); const lang = useLang();
return ( return (
@ -186,24 +193,4 @@ const LeftMain: FC<OwnProps> = ({
); );
}; };
function useAppOutdatedCheck() {
const [isAppOutdated, markIsAppOutdated] = useFlag(false);
useEffect(() => {
const timeout = window.setTimeout(markIsAppOutdated, APP_OUTDATED_TIMEOUT);
return () => {
clearTimeout(timeout);
};
}, [markIsAppOutdated]);
const { shouldRender, transitionClassNames } = useShowTransition(isAppOutdated);
const handleUpdateClick = () => {
window.location.reload();
};
return [shouldRender, transitionClassNames, handleUpdateClick] as const;
}
export default memo(LeftMain); export default memo(LeftMain);

View File

@ -230,7 +230,7 @@ const ChatResults: FC<OwnProps & StateProps> = ({
<div className="search-section"> <div className="search-section">
<h3 className="section-heading" dir={lang.isRtl ? 'auto' : undefined}> <h3 className="section-heading" dir={lang.isRtl ? 'auto' : undefined}>
{localResults.length > LESS_LIST_ITEMS_AMOUNT && ( {localResults.length > LESS_LIST_ITEMS_AMOUNT && (
<Link onClick={handleClickShowMoreLocal}> <Link className="Link" onClick={handleClickShowMoreLocal}>
{lang(shouldShowMoreLocal ? 'ChatList.Search.ShowLess' : 'ChatList.Search.ShowMore')} {lang(shouldShowMoreLocal ? 'ChatList.Search.ShowLess' : 'ChatList.Search.ShowMore')}
</Link> </Link>
)} )}
@ -254,7 +254,7 @@ const ChatResults: FC<OwnProps & StateProps> = ({
<div className="search-section"> <div className="search-section">
<h3 className="section-heading" dir={lang.isRtl ? 'auto' : undefined}> <h3 className="section-heading" dir={lang.isRtl ? 'auto' : undefined}>
{globalResults.length > LESS_LIST_ITEMS_AMOUNT && ( {globalResults.length > LESS_LIST_ITEMS_AMOUNT && (
<Link onClick={handleClickShowMoreGlobal}> <Link className="Link" onClick={handleClickShowMoreGlobal}>
{lang(shouldShowMoreGlobal ? 'ChatList.Search.ShowLess' : 'ChatList.Search.ShowMore')} {lang(shouldShowMoreGlobal ? 'ChatList.Search.ShowLess' : 'ChatList.Search.ShowMore')}
</Link> </Link>
)} )}

View File

@ -16,6 +16,7 @@ import useHistoryBack from '../../../../hooks/useHistoryBack';
import { useFolderManagerForChatsCount } from '../../../../hooks/useFolderManager'; import { useFolderManagerForChatsCount } from '../../../../hooks/useFolderManager';
import { selectCurrentLimit } from '../../../../global/selectors/limits'; import { selectCurrentLimit } from '../../../../global/selectors/limits';
import { selectIsCurrentUserPremium } from '../../../../global/selectors'; import { selectIsCurrentUserPremium } from '../../../../global/selectors';
import renderText from '../../../common/helpers/renderText';
import ListItem from '../../../ui/ListItem'; import ListItem from '../../../ui/ListItem';
import Button from '../../../ui/Button'; import Button from '../../../ui/Button';
@ -277,7 +278,7 @@ const SettingsFoldersMain: FC<OwnProps & StateProps> = ({
}} }}
> >
<span className="title"> <span className="title">
{folder.title} {renderText(folder.title, ['emoji'])}
{isBlocked && <i className="icon-lock-badge settings-folders-blocked-icon" />} {isBlocked && <i className="icon-lock-badge settings-folders-blocked-icon" />}
</span> </span>
<span className="subtitle">{folder.subtitle}</span> <span className="subtitle">{folder.subtitle}</span>
@ -307,7 +308,7 @@ const SettingsFoldersMain: FC<OwnProps & StateProps> = ({
> >
<div className="settings-folders-recommended-item"> <div className="settings-folders-recommended-item">
<div className="multiline-item"> <div className="multiline-item">
<span className="title">{folder.title}</span> <span className="title">{renderText(folder.title, ['emoji'])}</span>
<span className="subtitle">{folder.description}</span> <span className="subtitle">{folder.description}</span>
</div> </div>

View File

@ -39,6 +39,7 @@ import useForceUpdate from '../../hooks/useForceUpdate';
import { LOCATION_HASH } from '../../hooks/useHistoryBack'; import { LOCATION_HASH } from '../../hooks/useHistoryBack';
import useShowTransition from '../../hooks/useShowTransition'; import useShowTransition from '../../hooks/useShowTransition';
import { dispatchHeavyAnimationEvent } from '../../hooks/useHeavyAnimationCheck'; import { dispatchHeavyAnimationEvent } from '../../hooks/useHeavyAnimationCheck';
import useInterval from '../../hooks/useInterval';
import StickerSetModal from '../common/StickerSetModal.async'; import StickerSetModal from '../common/StickerSetModal.async';
import UnreadCount from '../common/UnreadCounter'; import UnreadCount from '../common/UnreadCounter';
@ -118,6 +119,7 @@ type StateProps = {
}; };
const NOTIFICATION_INTERVAL = 1000; const NOTIFICATION_INTERVAL = 1000;
const APP_OUTDATED_TIMEOUT_MS = 5 * 60 * 1000; // 5 min
let notificationInterval: number | undefined; let notificationInterval: number | undefined;
@ -189,6 +191,7 @@ const Main: FC<StateProps> = ({
loadCustomEmojis, loadCustomEmojis,
closePaymentModal, closePaymentModal,
clearReceipt, clearReceipt,
checkAppVersion,
} = getActions(); } = getActions();
if (DEBUG && !DEBUG_isLogged) { if (DEBUG && !DEBUG_isLogged) {
@ -203,6 +206,8 @@ const Main: FC<StateProps> = ({
} }
}, [connectionState, authState, sync]); }, [connectionState, authState, sync]);
useInterval(checkAppVersion, APP_OUTDATED_TIMEOUT_MS, true);
// Initial API calls // Initial API calls
useEffect(() => { useEffect(() => {
if (lastSyncTime) { if (lastSyncTime) {
@ -217,11 +222,12 @@ const Main: FC<StateProps> = ({
loadAttachMenuBots(); loadAttachMenuBots();
loadContactList(); loadContactList();
loadPremiumGifts(); loadPremiumGifts();
checkAppVersion();
} }
}, [ }, [
lastSyncTime, loadAnimatedEmojis, loadEmojiKeywords, loadNotificationExceptions, loadNotificationSettings, lastSyncTime, loadAnimatedEmojis, loadEmojiKeywords, loadNotificationExceptions, loadNotificationSettings,
loadTopInlineBots, updateIsOnline, loadAvailableReactions, loadAppConfig, loadAttachMenuBots, loadContactList, loadTopInlineBots, updateIsOnline, loadAvailableReactions, loadAppConfig, loadAttachMenuBots, loadContactList,
loadPremiumGifts, loadPremiumGifts, checkAppVersion,
]); ]);
// Language-based API calls // Language-based API calls

View File

@ -14,6 +14,7 @@ export const IS_PERF = process.env.APP_ENV === 'perf';
export const IS_BETA = process.env.APP_ENV === 'staging'; export const IS_BETA = process.env.APP_ENV === 'staging';
export const BETA_CHANGELOG_URL = 'https://telegra.ph/WebZ-Beta-04-01'; export const BETA_CHANGELOG_URL = 'https://telegra.ph/WebZ-Beta-04-01';
export const APP_VERSION_URL_PATH = '/version.txt';
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;

View File

@ -1,13 +1,11 @@
import { addActionHandler, setGlobal } from '../../index'; import { addActionHandler, getGlobal, setGlobal } from '../../index';
import type { ApiError } from '../../../api/types'; import type { ApiError } from '../../../api/types';
import { GLOBAL_STATE_CACHE_CUSTOM_EMOJI_LIMIT } from '../../../config'; import { APP_VERSION, APP_VERSION_URL_PATH, GLOBAL_STATE_CACHE_CUSTOM_EMOJI_LIMIT } from '../../../config';
import { IS_SINGLE_COLUMN_LAYOUT, IS_TABLET_COLUMN_LAYOUT } from '../../../util/environment'; import { IS_SINGLE_COLUMN_LAYOUT, IS_TABLET_COLUMN_LAYOUT } from '../../../util/environment';
import getReadableErrorText from '../../../util/getReadableErrorText'; import getReadableErrorText from '../../../util/getReadableErrorText';
import { import { selectChatMessage, selectCurrentMessageList, selectIsTrustedBot } from '../../selectors';
selectChatMessage, selectCurrentMessageList, selectIsTrustedBot,
} from '../../selectors';
import generateIdFor from '../../../util/generateIdFor'; import generateIdFor from '../../../util/generateIdFor';
import { unique } from '../../../util/iteratees'; import { unique } from '../../../util/iteratees';
@ -405,3 +403,21 @@ addActionHandler('updateLastRenderedCustomEmojis', (global, actions, payload) =>
}, },
}; };
}); });
addActionHandler('checkAppVersion', () => {
const APP_VERSION_REGEX = /^\d+\.\d+(\.\d+)?$/;
fetch(APP_VERSION_URL_PATH)
.then((response) => {
return response.text();
}).then((version) => {
version = version.trim();
if (APP_VERSION_REGEX.test(version) && version !== APP_VERSION) {
setGlobal({
...getGlobal(),
isUpdateAvailable: true,
});
}
});
});

View File

@ -15,6 +15,7 @@ export const INITIAL_STATE: GlobalState = {
newChatMembersProgress: NewChatMembersProgress.Closed, newChatMembersProgress: NewChatMembersProgress.Closed,
uiReadyState: 0, uiReadyState: 0,
serverTimeOffset: 0, serverTimeOffset: 0,
isUpdateAvailable: false,
authRememberMe: true, authRememberMe: true,
countryList: { countryList: {

View File

@ -147,6 +147,7 @@ export type GlobalState = {
connectionState?: ApiUpdateConnectionStateType; connectionState?: ApiUpdateConnectionStateType;
currentUserId?: string; currentUserId?: string;
isSyncing?: boolean; isSyncing?: boolean;
isUpdateAvailable?: boolean;
lastSyncTime?: number; lastSyncTime?: number;
serverTimeOffset: number; serverTimeOffset: number;
leftColumnWidth?: number; leftColumnWidth?: number;
@ -690,6 +691,7 @@ export interface ActionPayloads {
setInstallPrompt: { canInstall: boolean }; setInstallPrompt: { canInstall: boolean };
openLimitReachedModal: { limit: ApiLimitTypeWithModal }; openLimitReachedModal: { limit: ApiLimitTypeWithModal };
closeLimitReachedModal: never; closeLimitReachedModal: never;
checkAppVersion: never;
// Accounts // Accounts
reportPeer: { reportPeer: {