Various fixes for Web App bots (#2102)

This commit is contained in:
Alexander Zinchuk 2022-11-07 23:00:29 +04:00
parent d7ebc691e2
commit 923c946167
4 changed files with 42 additions and 23 deletions

View File

@ -179,7 +179,7 @@ export async function requestWebView({
startParam,
themeParams: theme ? buildInputThemeParams(theme) : undefined,
fromBotMenu: isFromBotMenu || undefined,
platform: 'web',
platform: 'webz',
...(sendAs && { sendAs: buildInputPeer(sendAs.id, sendAs.accessHash) }),
}));
@ -204,7 +204,7 @@ export async function requestSimpleWebView({
url,
bot: buildInputPeer(bot.id, bot.accessHash),
themeParams: theme ? buildInputThemeParams(theme) : undefined,
platform: 'web',
platform: 'webz',
}));
return result?.url;

View File

@ -103,6 +103,9 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
const prevPopupParams = usePrevious(popupParams);
const renderingPopupParams = popupParams || prevPopupParams;
// eslint-disable-next-line no-null/no-null
const frameRef = useRef<HTMLIFrameElement>(null);
const lang = useLang();
const {
url, buttonText, queryId,
@ -191,8 +194,8 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
]);
const {
ref, reloadFrame, sendEvent, sendViewport, sendTheme,
} = useWebAppFrame(isOpen, isSimple, handleEvent);
reloadFrame, sendEvent, sendViewport, sendTheme,
} = useWebAppFrame(frameRef, isOpen, isSimple, handleEvent);
const shouldShowMainButton = mainButton?.isVisible && mainButton.text.trim().length > 0;
@ -238,6 +241,10 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
});
}, [sendEvent]);
const handlePopupModalClose = useCallback(() => {
handlePopupClose();
}, [handlePopupClose]);
// Notify view that height changed
useOnChange(() => {
setTimeout(() => {
@ -427,13 +434,13 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
{isOpen && (
<>
<iframe
ref={ref}
className={buildClassName('web-app-frame', shouldDecreaseWebFrameSize && 'with-button')}
src={url}
title={`${bot?.firstName} Web App`}
sandbox={SANDBOX_ATTRIBUTES}
allow="camera; microphone; geolocation;"
allowFullScreen
ref={frameRef}
/>
<Button
className={buildClassName(
@ -465,7 +472,7 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
<Modal
isOpen={Boolean(popupParams)}
title={renderingPopupParams.title || NBSP}
onClose={handlePopupClose}
onClose={handlePopupModalClose}
hasCloseButton
className={buildClassName('web-app-popup', !renderingPopupParams.title?.trim().length && 'without-title')}
>

View File

@ -1,6 +1,6 @@
import useWindowSize from '../../../hooks/useWindowSize';
import { useCallback, useEffect, useRef } from '../../../lib/teact/teact';
import { extractCurrentThemeParams } from '../../../util/themeStyle';
import useWindowSize from '../../../hooks/useWindowSize';
export type PopupOptions = {
title: string;
@ -84,6 +84,7 @@ type WebAppOutboundEvent = {
height: number;
width?: number;
is_expanded?: boolean;
is_state_stable?: boolean;
};
} | {
eventType: 'theme_changed';
@ -141,10 +142,14 @@ const SCROLLBAR_STYLE = `* {
background-color: transparent;
}`;
const useWebAppFrame = (isOpen: boolean, isSimpleView: boolean, onEvent: (event: WebAppInboundEvent) => void) => {
// eslint-disable-next-line no-null/no-null
const ref = useRef<HTMLIFrameElement>(null);
const useWebAppFrame = (
ref: React.RefObject<HTMLIFrameElement>,
isOpen: boolean,
isSimpleView: boolean,
onEvent: (event: WebAppInboundEvent) => void,
) => {
const ignoreEventsRef = useRef<boolean>(false);
const lastFrameSizeRef = useRef<{ width: number; height: number; isResizing?: boolean }>();
const windowSize = useWindowSize();
const reloadFrame = useCallback((url: string) => {
@ -154,14 +159,14 @@ const useWebAppFrame = (isOpen: boolean, isSimpleView: boolean, onEvent: (event:
frame.addEventListener('load', () => {
frame.src = url;
}, { once: true });
}, []);
}, [ref]);
const sendEvent = useCallback((event: WebAppOutboundEvent) => {
if (!ref.current?.contentWindow) return;
ref.current.contentWindow.postMessage(JSON.stringify(event), '*');
}, []);
}, [ref]);
const sendViewport = useCallback(() => {
const sendViewport = useCallback((isNonStable?: boolean) => {
if (!ref.current) {
return;
}
@ -172,9 +177,10 @@ const useWebAppFrame = (isOpen: boolean, isSimpleView: boolean, onEvent: (event:
width,
height,
is_expanded: true,
is_state_stable: !isNonStable,
},
});
}, [sendEvent]);
}, [sendEvent, ref]);
const sendTheme = useCallback(() => {
sendEvent({
@ -201,7 +207,7 @@ const useWebAppFrame = (isOpen: boolean, isSimpleView: boolean, onEvent: (event:
const data = JSON.parse(event.data) as WebAppInboundEvent;
// Handle some app requests here to simplify hook usage
if (data.eventType === 'web_app_request_viewport') {
sendViewport();
sendViewport(windowSize.isResizing);
}
if (data.eventType === 'web_app_request_theme') {
@ -221,12 +227,14 @@ const useWebAppFrame = (isOpen: boolean, isSimpleView: boolean, onEvent: (event:
} catch (err) {
// Ignore other messages
}
}, [isSimpleView, onEvent, sendCustomStyle, sendTheme, sendViewport]);
}, [isSimpleView, onEvent, sendCustomStyle, sendTheme, sendViewport, windowSize]);
useEffect(() => {
if (windowSize) {
sendViewport();
}
const { width, height, isResizing } = windowSize;
if (lastFrameSizeRef.current && lastFrameSizeRef.current.width === width
&& lastFrameSizeRef.current.height === height && !lastFrameSizeRef.current.isResizing) return;
lastFrameSizeRef.current = { width, height, isResizing };
sendViewport(isResizing);
}, [sendViewport, windowSize]);
useEffect(() => {
@ -238,11 +246,13 @@ const useWebAppFrame = (isOpen: boolean, isSimpleView: boolean, onEvent: (event:
if (isOpen && ref.current?.contentWindow) {
sendViewport();
ignoreEventsRef.current = false;
} else {
lastFrameSizeRef.current = undefined;
}
}, [isOpen, sendViewport]);
}, [isOpen, sendViewport, ref]);
return {
ref, sendEvent, reloadFrame, sendViewport, sendTheme,
sendEvent, reloadFrame, sendViewport, sendTheme,
};
};

View File

@ -1,4 +1,4 @@
import { useEffect, useState } from '../lib/teact/teact';
import { useEffect, useMemo, useState } from '../lib/teact/teact';
import type { ApiDimensions } from '../api/types';
import { throttle } from '../util/schedulers';
@ -12,6 +12,8 @@ const useWindowSize = () => {
const [isResizing, setIsResizing] = useState(false);
const setIsResizingDebounced = useDebouncedCallback(setIsResizing, [], THROTTLE, true);
const result = useMemo(() => ({ ...size, isResizing }), [isResizing, size]);
useEffect(() => {
const throttledSetIsResizing = throttle(() => {
setIsResizing(true);
@ -34,7 +36,7 @@ const useWindowSize = () => {
};
}, [setIsResizingDebounced]);
return { ...size, isResizing };
return result;
};
export default useWindowSize;