mirror of
https://github.com/Qortal/qortal-mobile.git
synced 2025-04-25 04:17:53 +00:00
148 lines
5.1 KiB
TypeScript
148 lines
5.1 KiB
TypeScript
import React, { useContext, useEffect, useMemo, useState } from "react";
|
|
|
|
import { Avatar, Box, } from "@mui/material";
|
|
import { Add } from "@mui/icons-material";
|
|
import { MyContext, getBaseApiReact, isMobile } from "../../App";
|
|
|
|
import { executeEvent, subscribeToEvent, unsubscribeFromEvent } from "../../utils/events";
|
|
import { useFrame } from "react-frame-component";
|
|
import { useQortalMessageListener } from "./useQortalMessageListener";
|
|
|
|
|
|
|
|
|
|
export const AppViewer = React.forwardRef(({ app , hide}, iframeRef) => {
|
|
const { rootHeight } = useContext(MyContext);
|
|
// const iframeRef = useRef(null);
|
|
const { document, window: frameWindow } = useFrame();
|
|
const {path, history, changeCurrentIndex} = useQortalMessageListener(frameWindow, iframeRef, app?.tabId)
|
|
const [url, setUrl] = useState('')
|
|
console.log('historyreact', history)
|
|
|
|
useEffect(()=> {
|
|
setUrl(`${getBaseApiReact()}/render/${app?.service}/${app?.name}${app?.path != null ? `/${app?.path}` : ''}?theme=dark&identifier=${(app?.identifier != null && app?.identifier != 'null') ? app?.identifier : ''}`)
|
|
}, [app?.service, app?.name, app?.identifier, app?.path])
|
|
const defaultUrl = useMemo(()=> {
|
|
return url
|
|
}, [url])
|
|
|
|
|
|
|
|
const refreshAppFunc = (e) => {
|
|
const {tabId} = e.detail
|
|
if(tabId === app?.tabId){
|
|
const constructUrl = `${getBaseApiReact()}/render/${app?.service}/${app?.name}${path != null ? path : ''}?theme=dark&identifier=${app?.identifier != null ? app?.identifier : ''}&time=${new Date().getMilliseconds()}`
|
|
setUrl(constructUrl)
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
subscribeToEvent("refreshApp", refreshAppFunc);
|
|
|
|
return () => {
|
|
unsubscribeFromEvent("refreshApp", refreshAppFunc);
|
|
};
|
|
}, [app, path]);
|
|
|
|
// Function to navigate back in iframe
|
|
const navigateBackInIframe = async () => {
|
|
if (iframeRef.current && iframeRef.current.contentWindow && history?.currentIndex > 0) {
|
|
// Calculate the previous index and path
|
|
const previousPageIndex = history.currentIndex - 1;
|
|
const previousPath = history.customQDNHistoryPaths[previousPageIndex];
|
|
|
|
// Signal non-manual navigation
|
|
iframeRef.current.contentWindow.postMessage(
|
|
{ action: 'PERFORMING_NON_MANUAL', currentIndex: previousPageIndex }, '*'
|
|
);
|
|
console.log('previousPageIndex', previousPageIndex)
|
|
// Update the current index locally
|
|
changeCurrentIndex(previousPageIndex);
|
|
|
|
// Create a navigation promise with a 200ms timeout
|
|
const navigationPromise = new Promise((resolve, reject) => {
|
|
function handleNavigationSuccess(event) {
|
|
console.log('listeninghandlenav', event)
|
|
if (event.data?.action === 'NAVIGATION_SUCCESS' && event.data.path === previousPath) {
|
|
frameWindow.removeEventListener('message', handleNavigationSuccess);
|
|
resolve();
|
|
}
|
|
}
|
|
|
|
frameWindow.addEventListener('message', handleNavigationSuccess);
|
|
|
|
// Timeout after 200ms if no response
|
|
setTimeout(() => {
|
|
window.removeEventListener('message', handleNavigationSuccess);
|
|
reject(new Error("Navigation timeout"));
|
|
}, 200);
|
|
|
|
// Send the navigation command after setting up the listener and timeout
|
|
iframeRef.current.contentWindow.postMessage(
|
|
{ action: 'NAVIGATE_TO_PATH', path: previousPath, requestedHandler: 'UI' }, '*'
|
|
);
|
|
});
|
|
|
|
// Execute navigation promise and handle timeout fallback
|
|
try {
|
|
await navigationPromise;
|
|
console.log('Navigation succeeded within 200ms.');
|
|
} catch (error) {
|
|
|
|
setUrl(`${getBaseApiReact()}/render/${app?.service}/${app?.name}${previousPath != null ? previousPath : ''}?theme=dark&identifier=${(app?.identifier != null && app?.identifier != 'null') ? app?.identifier : ''}&time=${new Date().getMilliseconds()}&isManualNavigation=false`)
|
|
// iframeRef.current.contentWindow.location.href = previousPath; // Fallback URL update
|
|
}
|
|
} else {
|
|
console.log('Iframe not accessible or does not have a content window.');
|
|
}
|
|
};
|
|
|
|
const navigateBackAppFunc = (e) => {
|
|
|
|
navigateBackInIframe()
|
|
};
|
|
|
|
useEffect(() => {
|
|
if(!app?.tabId) return
|
|
subscribeToEvent(`navigateBackApp-${app?.tabId}`, navigateBackAppFunc);
|
|
|
|
return () => {
|
|
unsubscribeFromEvent(`navigateBackApp-${app?.tabId}`, navigateBackAppFunc);
|
|
};
|
|
}, [app, history]);
|
|
|
|
|
|
// Function to navigate back in iframe
|
|
const navigateForwardInIframe = async () => {
|
|
|
|
|
|
if (iframeRef.current && iframeRef.current.contentWindow) {
|
|
console.log('iframeRef.contentWindow', iframeRef.current.contentWindow);
|
|
iframeRef.current.contentWindow.postMessage(
|
|
{ action: 'NAVIGATE_FORWARD'},
|
|
'*'
|
|
);
|
|
} else {
|
|
console.log('Iframe not accessible or does not have a content window.');
|
|
}
|
|
};
|
|
|
|
|
|
return (
|
|
<Box sx={{
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
}}>
|
|
|
|
<iframe ref={iframeRef} style={{
|
|
height: !isMobile ? '100vh' : `calc(${rootHeight} - 60px - 45px )`,
|
|
border: 'none',
|
|
width: '100%'
|
|
}} id="browser-iframe" src={defaultUrl} sandbox="allow-scripts allow-same-origin allow-forms allow-downloads allow-modals" allow="fullscreen">
|
|
|
|
</iframe>
|
|
</Box>
|
|
|
|
);
|
|
});
|