mirror of
https://github.com/danog/telegram-tt.git
synced 2025-01-22 21:31:22 +01:00
Compare versions for "Update Telegram" button; Various UI fixes (#2022)
This commit is contained in:
parent
bf4812f6cf
commit
6d0c4e4b66
@ -4,14 +4,15 @@
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"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",
|
||||
"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: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",
|
||||
"print_version": "node -p -e \"require('./package.json').version\"",
|
||||
"inc_version": "echo $((`cat .patch-version` + 1)) > .patch-version && echo \"$(node -p -e \"require('./package.json').version.match(/^\\d+\\.\\d+/)[0]\").$(cat .patch-version)\"",
|
||||
"update_version": "npm run print_version --silent > ./public/version.txt",
|
||||
"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",
|
||||
"check": "tsc && stylelint \"**/*.{css,scss}\" && eslint . --ext .ts,.tsx,.js --ignore-pattern src/lib/gramjs",
|
||||
"check:fix": "npm run check -- --fix",
|
||||
|
1
public/version.txt
Normal file
1
public/version.txt
Normal file
@ -0,0 +1 @@
|
||||
1.51.1
|
@ -32,6 +32,7 @@ type StateProps = {
|
||||
hasPasscode?: boolean;
|
||||
nextSettingsScreen?: SettingsScreens;
|
||||
isChatOpen: boolean;
|
||||
isUpdateAvailable?: boolean;
|
||||
};
|
||||
|
||||
enum ContentType {
|
||||
@ -58,6 +59,7 @@ const LeftColumn: FC<StateProps> = ({
|
||||
hasPasscode,
|
||||
nextSettingsScreen,
|
||||
isChatOpen,
|
||||
isUpdateAvailable,
|
||||
}) => {
|
||||
const {
|
||||
setGlobalSearchQuery,
|
||||
@ -440,6 +442,7 @@ const LeftColumn: FC<StateProps> = ({
|
||||
onScreenSelect={handleSettingsScreenSelect}
|
||||
onReset={handleReset}
|
||||
shouldSkipTransition={shouldSkipHistoryAnimations}
|
||||
isUpdateAvailable={isUpdateAvailable}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -474,6 +477,7 @@ export default memo(withGlobal(
|
||||
settings: {
|
||||
nextScreen: nextSettingsScreen,
|
||||
},
|
||||
isUpdateAvailable,
|
||||
} = global;
|
||||
|
||||
const isChatOpen = Boolean(selectCurrentChat(global)?.id);
|
||||
@ -488,6 +492,7 @@ export default memo(withGlobal(
|
||||
hasPasscode,
|
||||
nextSettingsScreen,
|
||||
isChatOpen,
|
||||
isUpdateAvailable,
|
||||
};
|
||||
},
|
||||
)(LeftColumn));
|
||||
|
@ -43,6 +43,7 @@
|
||||
> span {
|
||||
padding-left: 0.5rem;
|
||||
padding-right: 0.5rem;
|
||||
white-space: pre;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,6 @@ import type { FolderEditDispatch } from '../../../hooks/reducers/useFoldersReduc
|
||||
|
||||
import { IS_TOUCH_ENV } from '../../../util/environment';
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
import useFlag from '../../../hooks/useFlag';
|
||||
import useShowTransition from '../../../hooks/useShowTransition';
|
||||
import useLang from '../../../hooks/useLang';
|
||||
|
||||
@ -30,6 +29,7 @@ type OwnProps = {
|
||||
contactsFilter: string;
|
||||
shouldSkipTransition?: boolean;
|
||||
foldersDispatch: FolderEditDispatch;
|
||||
isUpdateAvailable?: boolean;
|
||||
onSearchQuery: (query: string) => void;
|
||||
onContentChange: (content: LeftColumnContent) => void;
|
||||
onScreenSelect: (screen: SettingsScreens) => void;
|
||||
@ -38,7 +38,6 @@ type OwnProps = {
|
||||
|
||||
const TRANSITION_RENDER_COUNT = Object.keys(LeftColumnContent).length / 2;
|
||||
const BUTTON_CLOSE_DELAY_MS = 250;
|
||||
const APP_OUTDATED_TIMEOUT = 3 * 24 * 60 * 60 * 1000; // 3 days
|
||||
|
||||
let closeTimeout: number | undefined;
|
||||
|
||||
@ -49,6 +48,7 @@ const LeftMain: FC<OwnProps> = ({
|
||||
contactsFilter,
|
||||
shouldSkipTransition,
|
||||
foldersDispatch,
|
||||
isUpdateAvailable,
|
||||
onSearchQuery,
|
||||
onContentChange,
|
||||
onScreenSelect,
|
||||
@ -56,28 +56,13 @@ const LeftMain: FC<OwnProps> = ({
|
||||
}) => {
|
||||
const [isNewChatButtonShown, setIsNewChatButtonShown] = useState(IS_TOUCH_ENV);
|
||||
|
||||
const {
|
||||
shouldRender: shouldRenderUpdateButton,
|
||||
transitionClassNames: updateButtonClassNames,
|
||||
} = useShowTransition(isUpdateAvailable);
|
||||
|
||||
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(() => {
|
||||
if (content !== LeftColumnContent.ChatList) {
|
||||
return;
|
||||
@ -101,6 +86,30 @@ const LeftMain: FC<OwnProps> = ({
|
||||
}, 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(() => {
|
||||
let autoCloseTimeout: number | undefined;
|
||||
if (content !== LeftColumnContent.ChatList) {
|
||||
@ -119,8 +128,6 @@ const LeftMain: FC<OwnProps> = ({
|
||||
};
|
||||
}, [content]);
|
||||
|
||||
const [shouldRenderUpdateButton, updateButtonClassNames, handleUpdateClick] = useAppOutdatedCheck();
|
||||
|
||||
const lang = useLang();
|
||||
|
||||
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);
|
||||
|
@ -230,7 +230,7 @@ const ChatResults: FC<OwnProps & StateProps> = ({
|
||||
<div className="search-section">
|
||||
<h3 className="section-heading" dir={lang.isRtl ? 'auto' : undefined}>
|
||||
{localResults.length > LESS_LIST_ITEMS_AMOUNT && (
|
||||
<Link onClick={handleClickShowMoreLocal}>
|
||||
<Link className="Link" onClick={handleClickShowMoreLocal}>
|
||||
{lang(shouldShowMoreLocal ? 'ChatList.Search.ShowLess' : 'ChatList.Search.ShowMore')}
|
||||
</Link>
|
||||
)}
|
||||
@ -254,7 +254,7 @@ const ChatResults: FC<OwnProps & StateProps> = ({
|
||||
<div className="search-section">
|
||||
<h3 className="section-heading" dir={lang.isRtl ? 'auto' : undefined}>
|
||||
{globalResults.length > LESS_LIST_ITEMS_AMOUNT && (
|
||||
<Link onClick={handleClickShowMoreGlobal}>
|
||||
<Link className="Link" onClick={handleClickShowMoreGlobal}>
|
||||
{lang(shouldShowMoreGlobal ? 'ChatList.Search.ShowLess' : 'ChatList.Search.ShowMore')}
|
||||
</Link>
|
||||
)}
|
||||
|
@ -16,6 +16,7 @@ import useHistoryBack from '../../../../hooks/useHistoryBack';
|
||||
import { useFolderManagerForChatsCount } from '../../../../hooks/useFolderManager';
|
||||
import { selectCurrentLimit } from '../../../../global/selectors/limits';
|
||||
import { selectIsCurrentUserPremium } from '../../../../global/selectors';
|
||||
import renderText from '../../../common/helpers/renderText';
|
||||
|
||||
import ListItem from '../../../ui/ListItem';
|
||||
import Button from '../../../ui/Button';
|
||||
@ -277,7 +278,7 @@ const SettingsFoldersMain: FC<OwnProps & StateProps> = ({
|
||||
}}
|
||||
>
|
||||
<span className="title">
|
||||
{folder.title}
|
||||
{renderText(folder.title, ['emoji'])}
|
||||
{isBlocked && <i className="icon-lock-badge settings-folders-blocked-icon" />}
|
||||
</span>
|
||||
<span className="subtitle">{folder.subtitle}</span>
|
||||
@ -307,7 +308,7 @@ const SettingsFoldersMain: FC<OwnProps & StateProps> = ({
|
||||
>
|
||||
<div className="settings-folders-recommended-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>
|
||||
</div>
|
||||
|
||||
|
@ -39,6 +39,7 @@ import useForceUpdate from '../../hooks/useForceUpdate';
|
||||
import { LOCATION_HASH } from '../../hooks/useHistoryBack';
|
||||
import useShowTransition from '../../hooks/useShowTransition';
|
||||
import { dispatchHeavyAnimationEvent } from '../../hooks/useHeavyAnimationCheck';
|
||||
import useInterval from '../../hooks/useInterval';
|
||||
|
||||
import StickerSetModal from '../common/StickerSetModal.async';
|
||||
import UnreadCount from '../common/UnreadCounter';
|
||||
@ -118,6 +119,7 @@ type StateProps = {
|
||||
};
|
||||
|
||||
const NOTIFICATION_INTERVAL = 1000;
|
||||
const APP_OUTDATED_TIMEOUT_MS = 5 * 60 * 1000; // 5 min
|
||||
|
||||
let notificationInterval: number | undefined;
|
||||
|
||||
@ -189,6 +191,7 @@ const Main: FC<StateProps> = ({
|
||||
loadCustomEmojis,
|
||||
closePaymentModal,
|
||||
clearReceipt,
|
||||
checkAppVersion,
|
||||
} = getActions();
|
||||
|
||||
if (DEBUG && !DEBUG_isLogged) {
|
||||
@ -203,6 +206,8 @@ const Main: FC<StateProps> = ({
|
||||
}
|
||||
}, [connectionState, authState, sync]);
|
||||
|
||||
useInterval(checkAppVersion, APP_OUTDATED_TIMEOUT_MS, true);
|
||||
|
||||
// Initial API calls
|
||||
useEffect(() => {
|
||||
if (lastSyncTime) {
|
||||
@ -217,11 +222,12 @@ const Main: FC<StateProps> = ({
|
||||
loadAttachMenuBots();
|
||||
loadContactList();
|
||||
loadPremiumGifts();
|
||||
checkAppVersion();
|
||||
}
|
||||
}, [
|
||||
lastSyncTime, loadAnimatedEmojis, loadEmojiKeywords, loadNotificationExceptions, loadNotificationSettings,
|
||||
loadTopInlineBots, updateIsOnline, loadAvailableReactions, loadAppConfig, loadAttachMenuBots, loadContactList,
|
||||
loadPremiumGifts,
|
||||
loadPremiumGifts, checkAppVersion,
|
||||
]);
|
||||
|
||||
// Language-based API calls
|
||||
|
@ -14,6 +14,7 @@ export const IS_PERF = process.env.APP_ENV === 'perf';
|
||||
export const IS_BETA = process.env.APP_ENV === 'staging';
|
||||
|
||||
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_GRAMJS = false;
|
||||
|
@ -1,13 +1,11 @@
|
||||
import { addActionHandler, setGlobal } from '../../index';
|
||||
import { addActionHandler, getGlobal, setGlobal } from '../../index';
|
||||
|
||||
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 getReadableErrorText from '../../../util/getReadableErrorText';
|
||||
import {
|
||||
selectChatMessage, selectCurrentMessageList, selectIsTrustedBot,
|
||||
} from '../../selectors';
|
||||
import { selectChatMessage, selectCurrentMessageList, selectIsTrustedBot } from '../../selectors';
|
||||
import generateIdFor from '../../../util/generateIdFor';
|
||||
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,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -15,6 +15,7 @@ export const INITIAL_STATE: GlobalState = {
|
||||
newChatMembersProgress: NewChatMembersProgress.Closed,
|
||||
uiReadyState: 0,
|
||||
serverTimeOffset: 0,
|
||||
isUpdateAvailable: false,
|
||||
|
||||
authRememberMe: true,
|
||||
countryList: {
|
||||
|
@ -147,6 +147,7 @@ export type GlobalState = {
|
||||
connectionState?: ApiUpdateConnectionStateType;
|
||||
currentUserId?: string;
|
||||
isSyncing?: boolean;
|
||||
isUpdateAvailable?: boolean;
|
||||
lastSyncTime?: number;
|
||||
serverTimeOffset: number;
|
||||
leftColumnWidth?: number;
|
||||
@ -690,6 +691,7 @@ export interface ActionPayloads {
|
||||
setInstallPrompt: { canInstall: boolean };
|
||||
openLimitReachedModal: { limit: ApiLimitTypeWithModal };
|
||||
closeLimitReachedModal: never;
|
||||
checkAppVersion: never;
|
||||
|
||||
// Accounts
|
||||
reportPeer: {
|
||||
|
Loading…
x
Reference in New Issue
Block a user