import StyledPaint from "components/apps/Paint/StyledPaint"; import type { ComponentProcessProps } from "components/system/Apps/RenderComponent"; import StyledLoading from "components/system/Files/FileManager/StyledLoading"; import useFileDrop from "components/system/Files/FileManager/useFileDrop"; import useTitle from "components/system/Window/useTitle"; import { useFileSystem } from "contexts/fileSystem"; import { useProcesses } from "contexts/process"; import { useSession } from "contexts/session"; import type { WallpaperFit } from "contexts/session/types"; import { basename, dirname, join } from "path"; import { useCallback, useEffect, useRef, useState } from "react"; import { DESKTOP_PATH, IFRAME_CONFIG, ONE_TIME_PASSIVE_EVENT, PICUTRES_PATH, } from "utils/constants"; type JsPaint = { close: () => void; file_new: () => void; open_from_file: (file: File, fileHandle: string) => void; storage_quota_exceeded: () => void; systemHooks: { setWallpaperCentered: (canvas: HTMLCanvasElement) => void; setWallpaperTiled: (canvas: HTMLCanvasElement) => void; showOpenFileDialog: (props: { formats: unknown[]; }) => Promise<{ file: File }>; showSaveFileDialog: (props: { defaultFileName: string; getBlob: (mimeType: string) => Promise; }) => void; writeBlobToHandle: (fileHandle: string, blob: Blob) => Promise; }; }; const Paint: FC = ({ id }) => { const { closeWithTransition, processes: { [id]: { libs: [paintSrc = ""] = [], url = "" } = {} } = {}, } = useProcesses(); const { createPath, exists, readFile, updateFolder, writeFile } = useFileSystem(); const { foregroundId, setForegroundId, setWallpaper } = useSession(); const iframeRef = useRef(null); const [loaded, setLoaded] = useState(false); const [jsPaintInstance, setJsPaintInstance] = useState(); const { prependFileToTitle } = useTitle(id); const setWallpaperFromCanvas = useCallback( (fit: WallpaperFit) => (canvas: HTMLCanvasElement): void => { const wallpaperPath = join(PICUTRES_PATH, "wallpaper.png"); canvas.toBlob(async (blob) => { await writeFile( wallpaperPath, Buffer.from((await blob?.arrayBuffer()) as ArrayBuffer), true ); setWallpaper(wallpaperPath, fit); }); }, [setWallpaper, writeFile] ); const { onDragOver, onDrop } = useFileDrop({ id }); useEffect(() => { prependFileToTitle("Untitled"); }, [prependFileToTitle]); useEffect(() => { if (foregroundId !== id) { iframeRef.current?.contentWindow?.addEventListener( "click", () => setForegroundId(id), ONE_TIME_PASSIVE_EVENT ); } }, [foregroundId, id, setForegroundId]); useEffect(() => { const { contentWindow } = iframeRef.current || {}; if (loaded && contentWindow && !jsPaintInstance) { const jsPaint = contentWindow as unknown as JsPaint; const previousOpenFileDialog = jsPaint.systemHooks.showOpenFileDialog; const previousFileNew = jsPaint.file_new; setJsPaintInstance(jsPaint); jsPaint.file_new = () => { prependFileToTitle("Untitled"); previousFileNew(); }; jsPaint.systemHooks.setWallpaperTiled = setWallpaperFromCanvas("tile"); jsPaint.systemHooks.setWallpaperCentered = setWallpaperFromCanvas("center"); jsPaint.systemHooks.showOpenFileDialog = async (props) => { const { file } = await previousOpenFileDialog(props); prependFileToTitle(file.name); return { file }; }; jsPaint.close = () => closeWithTransition(id); jsPaint.storage_quota_exceeded = () => { // Ignore Storage Warning }; jsPaint.systemHooks.showSaveFileDialog = async ({ defaultFileName, getBlob, }) => updateFolder( DESKTOP_PATH, await createPath( `${defaultFileName}.png`, DESKTOP_PATH, Buffer.from(await (await getBlob("image/png")).arrayBuffer()) ) ); jsPaint.systemHooks.writeBlobToHandle = async (fileHandle, blob) => { if (await exists(fileHandle)) { await writeFile( fileHandle, Buffer.from(await blob.arrayBuffer()), true ); updateFolder(dirname(fileHandle), basename(fileHandle)); } }; contentWindow.addEventListener("dragover", onDragOver); contentWindow.addEventListener("drop", onDrop); } }, [ closeWithTransition, createPath, exists, id, jsPaintInstance, loaded, onDragOver, onDrop, prependFileToTitle, setWallpaperFromCanvas, updateFolder, writeFile, ]); useEffect(() => { if (jsPaintInstance && url) { readFile(url).then((buffer) => { jsPaintInstance.open_from_file(new File([buffer], url), url); prependFileToTitle(basename(url)); }); } }, [jsPaintInstance, prependFileToTitle, readFile, url]); return ( {!loaded && }