240 lines
6.7 KiB
TypeScript
240 lines
6.7 KiB
TypeScript
import type { FC } from '../lib/teact/teact';
|
|
import React, { useEffect, useLayoutEffect } from '../lib/teact/teact';
|
|
import { getActions, withGlobal } from '../global';
|
|
|
|
import type { GlobalState } from '../global/types';
|
|
import type { UiLoaderPage } from './common/UiLoader';
|
|
import type { ThemeKey } from '../types';
|
|
|
|
import { IS_INSTALL_PROMPT_SUPPORTED, IS_MULTITAB_SUPPORTED, PLATFORM_ENV } from '../util/windowEnvironment';
|
|
import {
|
|
DARK_THEME_BG_COLOR, INACTIVE_MARKER, LIGHT_THEME_BG_COLOR, PAGE_TITLE,
|
|
} from '../config';
|
|
import { selectTabState, selectTheme } from '../global/selectors';
|
|
import { updateSizes } from '../util/windowSize';
|
|
import { addActiveTabChangeListener } from '../util/activeTabMonitor';
|
|
import { hasStoredSession } from '../util/sessions';
|
|
import buildClassName from '../util/buildClassName';
|
|
import { parseInitialLocationHash } from '../util/routing';
|
|
import { setupBeforeInstallPrompt } from '../util/installPrompt';
|
|
|
|
import useFlag from '../hooks/useFlag';
|
|
import usePrevious from '../hooks/usePrevious';
|
|
import useAppLayout from '../hooks/useAppLayout';
|
|
|
|
import Auth from './auth/Auth';
|
|
import Main from './main/Main.async';
|
|
import LockScreen from './main/LockScreen.async';
|
|
import AppInactive from './main/AppInactive';
|
|
import Transition from './ui/Transition';
|
|
import UiLoader from './common/UiLoader';
|
|
// import Test from './test/TestUpdateRef';
|
|
|
|
import styles from './App.module.scss';
|
|
|
|
type StateProps = {
|
|
authState: GlobalState['authState'];
|
|
isScreenLocked?: boolean;
|
|
hasPasscode?: boolean;
|
|
isInactiveAuth?: boolean;
|
|
hasWebAuthTokenFailed?: boolean;
|
|
theme: ThemeKey;
|
|
};
|
|
|
|
enum AppScreens {
|
|
auth,
|
|
main,
|
|
lock,
|
|
inactive,
|
|
}
|
|
|
|
const TRANSITION_RENDER_COUNT = Object.keys(AppScreens).length / 2;
|
|
const INACTIVE_PAGE_TITLE = `${PAGE_TITLE} ${INACTIVE_MARKER}`;
|
|
|
|
const App: FC<StateProps> = ({
|
|
authState,
|
|
isScreenLocked,
|
|
hasPasscode,
|
|
isInactiveAuth,
|
|
hasWebAuthTokenFailed,
|
|
theme,
|
|
}) => {
|
|
const { disconnect } = getActions();
|
|
|
|
const [isInactive, markInactive, unmarkInactive] = useFlag(false);
|
|
const { isMobile } = useAppLayout();
|
|
const isMobileOs = PLATFORM_ENV === 'iOS' || PLATFORM_ENV === 'Android';
|
|
|
|
useEffect(() => {
|
|
if (IS_INSTALL_PROMPT_SUPPORTED) {
|
|
setupBeforeInstallPrompt();
|
|
}
|
|
}, []);
|
|
|
|
// Prevent drop on elements that do not accept it
|
|
useEffect(() => {
|
|
const body = document.body;
|
|
const handleDrag = (e: DragEvent) => {
|
|
e.preventDefault();
|
|
if (!e.dataTransfer) return;
|
|
if (!(e.target as HTMLElement).dataset.dropzone) {
|
|
e.dataTransfer.dropEffect = 'none';
|
|
} else {
|
|
e.dataTransfer.dropEffect = 'copy';
|
|
}
|
|
};
|
|
const handleDrop = (e: DragEvent) => {
|
|
e.preventDefault();
|
|
};
|
|
body.addEventListener('drop', handleDrop);
|
|
body.addEventListener('dragover', handleDrag);
|
|
body.addEventListener('dragenter', handleDrag);
|
|
|
|
return () => {
|
|
body.removeEventListener('drop', handleDrop);
|
|
body.removeEventListener('dragover', handleDrag);
|
|
body.removeEventListener('dragenter', handleDrag);
|
|
};
|
|
}, []);
|
|
|
|
// return <Test />;
|
|
|
|
let activeKey: number;
|
|
let page: UiLoaderPage | undefined;
|
|
|
|
if (isInactive) {
|
|
activeKey = AppScreens.inactive;
|
|
} else if (isScreenLocked) {
|
|
page = 'lock';
|
|
activeKey = AppScreens.lock;
|
|
} else if (authState) {
|
|
switch (authState) {
|
|
case 'authorizationStateWaitPhoneNumber':
|
|
page = 'authPhoneNumber';
|
|
activeKey = AppScreens.auth;
|
|
break;
|
|
case 'authorizationStateWaitCode':
|
|
page = 'authCode';
|
|
activeKey = AppScreens.auth;
|
|
break;
|
|
case 'authorizationStateWaitPassword':
|
|
page = 'authPassword';
|
|
activeKey = AppScreens.auth;
|
|
break;
|
|
case 'authorizationStateWaitRegistration':
|
|
activeKey = AppScreens.auth;
|
|
break;
|
|
case 'authorizationStateWaitQrCode':
|
|
page = 'authQrCode';
|
|
activeKey = AppScreens.auth;
|
|
break;
|
|
case 'authorizationStateClosed':
|
|
case 'authorizationStateClosing':
|
|
case 'authorizationStateLoggingOut':
|
|
case 'authorizationStateReady':
|
|
page = 'main';
|
|
activeKey = AppScreens.main;
|
|
break;
|
|
}
|
|
} else if (hasStoredSession(true)) {
|
|
page = 'main';
|
|
activeKey = AppScreens.main;
|
|
} else if (hasPasscode) {
|
|
activeKey = AppScreens.lock;
|
|
} else {
|
|
page = isMobileOs ? 'authPhoneNumber' : 'authQrCode';
|
|
activeKey = AppScreens.auth;
|
|
}
|
|
|
|
if (activeKey !== AppScreens.lock
|
|
&& activeKey !== AppScreens.inactive
|
|
&& activeKey !== AppScreens.main
|
|
&& parseInitialLocationHash()?.tgWebAuthToken
|
|
&& !hasWebAuthTokenFailed) {
|
|
page = 'main';
|
|
activeKey = AppScreens.main;
|
|
}
|
|
|
|
useEffect(() => {
|
|
updateSizes();
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (IS_MULTITAB_SUPPORTED) return;
|
|
|
|
addActiveTabChangeListener(() => {
|
|
disconnect();
|
|
document.title = INACTIVE_PAGE_TITLE;
|
|
|
|
markInactive();
|
|
});
|
|
}, [activeKey, disconnect, markInactive]);
|
|
|
|
useEffect(() => {
|
|
if (isInactiveAuth) {
|
|
document.title = INACTIVE_PAGE_TITLE;
|
|
markInactive();
|
|
} else {
|
|
document.title = PAGE_TITLE;
|
|
unmarkInactive();
|
|
}
|
|
}, [isInactiveAuth, markInactive, unmarkInactive]);
|
|
|
|
const prevActiveKey = usePrevious(activeKey);
|
|
|
|
// eslint-disable-next-line consistent-return
|
|
function renderContent() {
|
|
switch (activeKey) {
|
|
case AppScreens.auth:
|
|
return <Auth />;
|
|
case AppScreens.main:
|
|
return <Main isMobile={isMobile} />;
|
|
case AppScreens.lock:
|
|
return <LockScreen isLocked={isScreenLocked} />;
|
|
case AppScreens.inactive:
|
|
return <AppInactive />;
|
|
}
|
|
}
|
|
|
|
useLayoutEffect(() => {
|
|
document.body.classList.add(styles.bg);
|
|
}, []);
|
|
|
|
useLayoutEffect(() => {
|
|
document.body.style.setProperty(
|
|
'--theme-background-color',
|
|
theme === 'dark' ? DARK_THEME_BG_COLOR : LIGHT_THEME_BG_COLOR,
|
|
);
|
|
}, [theme]);
|
|
|
|
return (
|
|
<UiLoader page={page} isMobile={isMobile}>
|
|
<Transition
|
|
name="fade"
|
|
activeKey={activeKey}
|
|
shouldCleanup
|
|
className={buildClassName(
|
|
'full-height',
|
|
(activeKey === AppScreens.auth || prevActiveKey === AppScreens.auth) && 'is-auth',
|
|
)}
|
|
renderCount={TRANSITION_RENDER_COUNT}
|
|
>
|
|
{renderContent}
|
|
</Transition>
|
|
</UiLoader>
|
|
);
|
|
};
|
|
|
|
export default withGlobal(
|
|
(global): StateProps => {
|
|
return {
|
|
authState: global.authState,
|
|
isScreenLocked: global.passcode?.isScreenLocked,
|
|
hasPasscode: global.passcode?.hasPasscode,
|
|
isInactiveAuth: selectTabState(global).isInactive,
|
|
hasWebAuthTokenFailed: global.hasWebAuthTokenFailed || global.hasWebAuthTokenPasswordRequired,
|
|
theme: selectTheme(global),
|
|
};
|
|
},
|
|
)(App);
|