From d7cd46213ce9d9954fe01554cab5a813be867f36 Mon Sep 17 00:00:00 2001 From: YeonV Date: Mon, 16 Dec 2024 16:55:11 +0100 Subject: [PATCH] FileDropper: scenePlaylist & virtualOrder --- src/App.tsx | 10 +- src/components/DnD/OrderListDialog.tsx | 2 +- src/store/ui/storeDialogs.tsx | 15 +++ src/utils/FiledropProvider.tsx | 125 +++++++++++++++++++++++++ 4 files changed, 145 insertions(+), 7 deletions(-) create mode 100644 src/utils/FiledropProvider.tsx diff --git a/src/App.tsx b/src/App.tsx index 98fd1aa0..c605a4e7 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -2,7 +2,7 @@ import { useEffect, useMemo } from 'react' import { createTheme, ThemeProvider } from '@mui/material/styles' import { SnackbarProvider } from 'notistack' import isElectron from 'is-electron' -import { Box, CssBaseline } from '@mui/material' +import { CssBaseline } from '@mui/material' import Cookies from 'universal-cookie' import ws, { WsContext, HandleWs } from './utils/Websocket' import useStore from './store/useStore' @@ -16,6 +16,7 @@ import { ledfxThemes, ledfxTheme, common } from './themes/AppThemes' import xmas from './assets/xmas.png' import newyear from './assets/fireworks.jpg' import login from './utils/login' +import FiledropProvider from './utils/FiledropProvider' export default function App() { const { height, width } = useWindowDimensions() @@ -220,13 +221,10 @@ export default function App() { - + } /> - + {features.waves && ( diff --git a/src/components/DnD/OrderListDialog.tsx b/src/components/DnD/OrderListDialog.tsx index 2c9790de..55a22d19 100644 --- a/src/components/DnD/OrderListDialog.tsx +++ b/src/components/DnD/OrderListDialog.tsx @@ -38,7 +38,7 @@ const OrderListDialog: FC = ({ onOpen() } } - console.log('virtualOrder', virtualOrder) + const handleClose = () => { setOpen(false) } diff --git a/src/store/ui/storeDialogs.tsx b/src/store/ui/storeDialogs.tsx index b0442dbe..c47fc5b8 100644 --- a/src/store/ui/storeDialogs.tsx +++ b/src/store/ui/storeDialogs.tsx @@ -48,6 +48,10 @@ const storeDialogs = (set: any) => ({ effectType: { open: false, edit: false + }, + filedrop: { + open: false, + edit: false } }, assistant: { @@ -88,6 +92,17 @@ const storeDialogs = (set: any) => ({ false, 'api/dialog/nohost' ), + setDialogOpenFileDrop: (open: boolean, edit?: boolean) => + set( + produce((state: IStore) => { + state.dialogs.filedrop = { + open, + edit: edit || false + } + }), + false, + 'api/dialog/FileDrop' + ), setDialogOpenAddScene: ( open: boolean, edit?: boolean, diff --git a/src/utils/FiledropProvider.tsx b/src/utils/FiledropProvider.tsx new file mode 100644 index 00000000..1aa93437 --- /dev/null +++ b/src/utils/FiledropProvider.tsx @@ -0,0 +1,125 @@ +import { + Box, + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle +} from '@mui/material' +import { useCallback, useState } from 'react' +import isElectron from 'is-electron' +import useStore from '../store/useStore' + +const FiledropProvider = ({ children }: { children: React.ReactNode }) => { + const [title, setTitle] = useState('LedFx JSON detected') + const [newData, setNewData] = useState(null) + const showSnackbar = useStore((state) => state.ui.showSnackbar) + const open = useStore((state) => state.dialogs.filedrop.open) + const virtualOrder = useStore((state) => state.virtualOrder) + const setVirtualOrder = useStore((state) => state.setVirtualOrder) + const setDialogOpenFileDrop = useStore((state) => state.setDialogOpenFileDrop) + const setScenePL = useStore((state) => state.setScenePL) + const setScenePLintervals = useStore((state) => state.setScenePLintervals) + + const handleJsonFile = useCallback( + async (e: any) => { + const fileReader = new FileReader() + fileReader.readAsText(e.target.files[0], 'UTF-8') + fileReader.onload = (ev: any) => { + const data = JSON.parse(ev.target.result) + if (!data) { + showSnackbar('error', 'Invalid file') + return + } + if (data.virtualOrder) { + const newOrder = data.virtualOrder + const oldVirtIds = virtualOrder.map((o: any) => o.virtId) + const newVirtIds = newOrder.map((o: any) => o.virtId) + if ( + newOrder.length === virtualOrder.length && + oldVirtIds.sort().join(',') === newVirtIds.sort().join(',') + ) { + setTitle('New Device Order detected') + setNewData({ type: 'virtualOrder', data: newOrder }) + setDialogOpenFileDrop(true) + } else { + showSnackbar('warning', 'Order file does not match') + } + } else if (data.scenePL || data.scenePLintervals) { + setTitle('New Scene Playlist detected') + setNewData({ type: 'scenePlaylist', data }) + setDialogOpenFileDrop(true) + } else { + showSnackbar('error', 'Invalid file') + } + } + }, + [setDialogOpenFileDrop, showSnackbar, virtualOrder] + ) + + const handleDrop = useCallback( + (e: React.DragEvent) => { + e.preventDefault() + const file = e.dataTransfer.files[0] + if (file && file.type === 'application/json') { + console.log('file', file) + handleJsonFile({ target: { files: [file] } }) + } else { + showSnackbar('error', 'Please drop a valid JSON file') + } + }, + [handleJsonFile, showSnackbar] + ) + + const handleDragOver = (e: React.DragEvent) => { + e.preventDefault() + } + + const handleClose = () => { + setDialogOpenFileDrop(false) + } + + const handleSave = () => { + showSnackbar('info', 'saving...') + if (newData) { + switch (newData.type) { + case 'virtualOrder': + setVirtualOrder(newData.data) + showSnackbar('success', 'Order updated') + break + case 'scenePlaylist': + if (newData.data.scenePL) setScenePL(newData.data.scenePL) + if (newData.data.scenePLintervals) + setScenePLintervals(newData.data.scenePLintervals) + showSnackbar('success', 'Scene Playlist updated') + break + default: + showSnackbar('error', 'Unknown data type') + } + } + setDialogOpenFileDrop(false) + } + + return ( + + {children} + + {title} + + Would you like to import it and overwrite current? + + + + + + + + ) +} + +export default FiledropProvider