Connection State: Support browser online state, add animation

This commit is contained in:
Alexander Zinchuk 2021-06-24 18:42:25 +03:00
parent 1cc1893fef
commit c92f7a42df
5 changed files with 57 additions and 17 deletions

View File

@ -1,9 +1,7 @@
import React, { FC } from '../../lib/teact/teact'; import React, { memo, FC } from '../../lib/teact/teact';
import { withGlobal } from '../../lib/teact/teactn';
import { GlobalState } from '../../global/types'; import { GlobalState } from '../../global/types';
import { pick } from '../../util/iteratees';
import useLang from '../../hooks/useLang'; import useLang from '../../hooks/useLang';
import Spinner from '../ui/Spinner'; import Spinner from '../ui/Spinner';
@ -12,12 +10,10 @@ import './ConnectionState.scss';
type StateProps = Pick<GlobalState, 'connectionState'>; type StateProps = Pick<GlobalState, 'connectionState'>;
const ConnectionState: FC<StateProps> = ({ connectionState }) => { const ConnectionState: FC<StateProps> = () => {
const lang = useLang(); const lang = useLang();
const isConnecting = connectionState === 'connectionStateConnecting'; return (
return isConnecting && (
<div id="ConnectionState" dir={lang.isRtl ? 'rtl' : undefined}> <div id="ConnectionState" dir={lang.isRtl ? 'rtl' : undefined}>
<Spinner color="black" /> <Spinner color="black" />
<div className="state-text">{lang('WaitingForNetwork')}</div> <div className="state-text">{lang('WaitingForNetwork')}</div>
@ -25,6 +21,4 @@ const ConnectionState: FC<StateProps> = ({ connectionState }) => {
); );
}; };
export default withGlobal( export default memo(ConnectionState);
(global): StateProps => pick(global, ['connectionState']),
)(ConnectionState);

View File

@ -6,9 +6,20 @@
overflow: hidden; overflow: hidden;
z-index: 1; z-index: 1;
.connection-state-wrapper {
position: absolute;
top: 3.75rem;
width: 100%;
}
> .Transition { > .Transition {
flex: 1; flex: 1;
overflow: hidden; overflow: hidden;
transition: transform 300ms ease;
&.pull-down {
transform: translateY(3.75rem);
}
} }
.ChatFolders { .ChatFolders {

View File

@ -1,10 +1,14 @@
import React, { import React, {
FC, memo, useState, useRef, useCallback, useEffect, FC, useState, useRef, useCallback, useEffect,
} from '../../../lib/teact/teact'; } from '../../../lib/teact/teact';
import { withGlobal } from '../../../lib/teact/teactn';
import { GlobalState } from '../../../global/types';
import { LeftColumnContent } from '../../../types'; import { LeftColumnContent } from '../../../types';
import { IS_TOUCH_ENV } from '../../../util/environment'; import { IS_TOUCH_ENV } from '../../../util/environment';
import { pick } from '../../../util/iteratees';
import useBrowserOnline from '../../../hooks/useBrowserOnline';
import Transition from '../../ui/Transition'; import Transition from '../../ui/Transition';
import LeftMainHeader from './LeftMainHeader'; import LeftMainHeader from './LeftMainHeader';
@ -13,6 +17,7 @@ import ChatFolders from './ChatFolders';
import LeftSearch from '../search/LeftSearch.async'; import LeftSearch from '../search/LeftSearch.async';
import ContactList from './ContactList.async'; import ContactList from './ContactList.async';
import NewChatButton from '../NewChatButton'; import NewChatButton from '../NewChatButton';
import ShowTransition from '../../ui/ShowTransition';
import './LeftMain.scss'; import './LeftMain.scss';
@ -26,7 +31,7 @@ type OwnProps = {
onReset: () => void; onReset: () => void;
}; };
type StateProps = {}; type StateProps = Pick<GlobalState, 'connectionState'>;
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;
@ -40,9 +45,13 @@ const LeftMain: FC<OwnProps & StateProps> = ({
onSearchQuery, onSearchQuery,
onContentChange, onContentChange,
onReset, onReset,
connectionState,
}) => { }) => {
const [isNewChatButtonShown, setIsNewChatButtonShown] = useState(IS_TOUCH_ENV); const [isNewChatButtonShown, setIsNewChatButtonShown] = useState(IS_TOUCH_ENV);
const isBrowserOnline = useBrowserOnline();
const isConnecting = !isBrowserOnline || connectionState === 'connectionStateConnecting';
const isMouseInside = useRef(false); const isMouseInside = useRef(false);
const handleSelectSettings = useCallback(() => { const handleSelectSettings = useCallback(() => {
@ -121,13 +130,16 @@ const LeftMain: FC<OwnProps & StateProps> = ({
onSelectArchived={handleSelectArchived} onSelectArchived={handleSelectArchived}
onReset={onReset} onReset={onReset}
/> />
<ConnectionState /> <ShowTransition isOpen={isConnecting} isCustom className="connection-state-wrapper opacity-transition slow">
{() => <ConnectionState />}
</ShowTransition>
<Transition <Transition
name="zoom-fade" name="zoom-fade"
renderCount={TRANSITION_RENDER_COUNT} renderCount={TRANSITION_RENDER_COUNT}
activeKey={content} activeKey={content}
shouldCleanup shouldCleanup
cleanupExceptionKey={LeftColumnContent.ChatList} cleanupExceptionKey={LeftColumnContent.ChatList}
className={isConnecting ? 'pull-down' : undefined}
> >
{(isActive) => { {(isActive) => {
switch (content) { switch (content) {
@ -159,4 +171,6 @@ const LeftMain: FC<OwnProps & StateProps> = ({
); );
}; };
export default memo(LeftMain); export default withGlobal<OwnProps>(
(global): StateProps => pick(global, ['connectionState']),
)(LeftMain);

View File

@ -1,9 +1,9 @@
import { useEffect } from '../lib/teact/teact'; import { useEffect } from '../lib/teact/teact';
export default ( export default function useBackgroundMode(
onBlur: AnyToVoidFunction, onBlur: AnyToVoidFunction,
onFocus: AnyToVoidFunction, onFocus: AnyToVoidFunction,
) => { ) {
useEffect(() => { useEffect(() => {
if (!document.hasFocus()) { if (!document.hasFocus()) {
onBlur(); onBlur();
@ -17,4 +17,4 @@ export default (
window.removeEventListener('blur', onBlur); window.removeEventListener('blur', onBlur);
}; };
}, [onBlur, onFocus]); }, [onBlur, onFocus]);
}; }

View File

@ -0,0 +1,21 @@
import { useEffect, useState } from '../lib/teact/teact';
export default function useBrowserOnline() {
const [isOnline, setIsOnline] = useState(window.navigator.onLine);
useEffect(() => {
function handleChange() {
setIsOnline(window.navigator.onLine);
}
window.addEventListener('online', handleChange);
window.addEventListener('offline', handleChange);
return () => {
window.removeEventListener('offline', handleChange);
window.removeEventListener('online', handleChange);
};
}, []);
return isOnline;
}