diff --git a/index.html b/index.html index ff93803..57071a9 100644 --- a/index.html +++ b/index.html @@ -1,10 +1,10 @@ - + - Tauri + React + Typescript + byte-me diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index df4051b..e2be1cd 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -343,6 +343,7 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" name = "byte-me" version = "0.1.0" dependencies = [ + "ffprobe", "serde", "serde_json", "tauri", @@ -938,6 +939,16 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "ffprobe" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ffef835e1f9ac151db5bb2adbb95c9dfe1f315f987f011dd89cd655b4e9a52c" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "field-offset" version = "0.3.6" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 7a19f27..d808f48 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -22,4 +22,5 @@ tauri = { version = "2", features = [] } tauri-plugin-opener = "2" serde = { version = "1", features = ["derive"] } serde_json = "1" +ffprobe = "0.4.0" diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 4a277ef..d1319e6 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,14 +1,34 @@ -// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/ +use std::path::Path; + #[tauri::command] -fn greet(name: &str) -> String { - format!("Hello, {}! You've been greeted from Rust!", name) +fn has_streams(paths: Vec) -> Result, String> { + let mut results = Vec::with_capacity(paths.len()); + for path_str in paths { + let path = Path::new(&path_str); + if !path.is_file() { + results.push(false); + continue; + } + + match ffprobe::ffprobe(&path_str) { + Ok(info) => { + dbg!(info); + results.push(true); + }, + Err(err) => { + eprintln!("Could not analyze file with ffprobe: {:?}", err); + results.push(false); + } + } + } + Ok(results) } #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { tauri::Builder::default() .plugin(tauri_plugin_opener::init()) - .invoke_handler(tauri::generate_handler![greet]) + .invoke_handler(tauri::generate_handler![has_streams]) .run(tauri::generate_context!()) .expect("error while running tauri application"); } diff --git a/src/App.css b/src/App.css deleted file mode 100644 index f7de85b..0000000 --- a/src/App.css +++ /dev/null @@ -1,109 +0,0 @@ -:root { - font-family: Inter, Avenir, Helvetica, Arial, sans-serif; - font-size: 16px; - line-height: 24px; - font-weight: 400; - - color: #0f0f0f; - background-color: #f6f6f6; - - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - -webkit-text-size-adjust: 100%; -} - -.container { - margin: 0; - padding-top: 10vh; - display: flex; - flex-direction: column; - justify-content: center; - text-align: center; -} - -.logo { - height: 6em; - padding: 1.5em; - will-change: filter; - transition: 0.75s; -} - -.logo.tauri:hover { - filter: drop-shadow(0 0 2em #24c8db); -} - -.row { - display: flex; - justify-content: center; -} - -a { - font-weight: 500; - color: #646cff; - text-decoration: inherit; -} - -a:hover { - color: #535bf2; -} - -h1 { - text-align: center; -} - -input, -button { - border-radius: 8px; - border: 1px solid transparent; - padding: 0.6em 1.2em; - font-size: 1em; - font-weight: 500; - font-family: inherit; - color: #0f0f0f; - background-color: #ffffff; - transition: border-color 0.25s; - box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2); -} - -button { - cursor: pointer; -} - -button:hover { - border-color: #396cd8; -} -button:active { - border-color: #396cd8; - background-color: #e8e8e8; -} - -input, -button { - outline: none; -} - -#greet-input { - margin-right: 5px; -} - -@media (prefers-color-scheme: dark) { - :root { - color: #f6f6f6; - background-color: #2f2f2f; - } - - a:hover { - color: #24c8db; - } - - input, - button { - color: #ffffff; - background-color: #0f0f0f98; - } - button:active { - background-color: #0f0f0f69; - } -} diff --git a/src/App.tsx b/src/App.tsx index 25f5c0c..e3a5d95 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,26 +1,26 @@ -import { ResponsiveLine } from "@nivo/line"; -import { formatBytes } from "./lib/format.js"; - type Frame = { id: string; data: { x: string | number; y: number }[]; }; import { getCurrentWebview } from "@tauri-apps/api/webview"; -import { useEffect } from "react"; +import { useEffect, useRef, useState } from "react"; +import Graph from "./components/Graph.js"; +import DropOverlay from "./components/drop-overlay.js"; function App() { const data: Frame[] = []; + const [paths, setPaths] = useState([]); useEffect(() => { const unlistenPromise = getCurrentWebview().onDragDropEvent( - async (event) => { - if (event.payload.type === "over") { - console.log("User hovering", event.payload.position); - } else if (event.payload.type === "drop") { - console.log("User dropped", event.payload.paths); - } else { - console.log("File drop cancelled"); + async ({ payload }) => { + if (payload.type === "enter") { + setPaths(payload.paths); + console.log("User hovering", payload); + } else if (payload.type === "leave" || payload.type === "drop") { + setPaths([]); + console.log("User left", payload); } } ); @@ -34,106 +34,7 @@ function App() { }; }, []); - // const data: Frame[] = useMemo(() => - // // Array.from({ length: 4 }, (_, i) => { - // // const d = Math.random(); - // // const g = Math.random(); - // // return { - // // id: `file-${i}`, - // // data: Array.from({ length: 500 }, (_, j) => { - // // if (Math.random() < 0.5) return null; - // // return { - // // x: j, - // // y: Math.random() * 256 * d + (1 - g) * 1024, - // // }; - // // }).filter((i) => i !== null), - // // }; - // // }), - // [] - // ); - - console.log(data); - - const graph = ( - formatBytes(v * 1024 * 53), - }} - pointSize={10} - colors={[ - "#3e8faf", - "#c4a7e7", - "#f5c276", - "#EA9B96", - "#EB7092", - "#9CCFD8", - ]} - // pointColor={{ modifiers: [["brighter", 1100]] }} - pointBorderWidth={0} - pointBorderColor={{ from: "seriesColor" }} - pointLabelYOffset={-12} - enableSlices={"x"} - enableTouchCrosshair={true} - useMesh={true} - legends={[ - { - anchor: "bottom-right", - direction: "column", - translateX: 100, - itemWidth: 80, - itemHeight: 22, - symbolShape: "circle", - }, - ]} - /> - ); + const graph = ; return (
-
-
-
- Drag and Drop to Add -
-
-
+ {graph}
); diff --git a/src/components/drop-overlay.tsx b/src/components/drop-overlay.tsx new file mode 100644 index 0000000..841cee4 --- /dev/null +++ b/src/components/drop-overlay.tsx @@ -0,0 +1,46 @@ +import { invoke } from "@tauri-apps/api/core"; +import { useEffect, useState } from "react"; + +type DropOverlayProps = { + paths: string[]; +}; + +type Status = "hidden" | "loading" | "ready" | "error"; + +const DropOverlay = ({ paths }: DropOverlayProps) => { + const [status, setStatus] = useState("hidden"); + + useEffect(() => { + if (paths.length === 0) { + setStatus("hidden"); + return; + } + + setStatus("loading"); + invoke("has_streams", { paths }).then((result) => { + setStatus(result ? "ready" : "error"); + }); + }, [paths]); + + return ( +
+
+
+ {status === "loading" + ? "Loading..." + : status === "ready" + ? "Ready" + : status === "error" + ? "Error" + : "Hidden"} +
+
+
+ ); +}; + +export default DropOverlay; diff --git a/src/components/graph.tsx b/src/components/graph.tsx new file mode 100644 index 0000000..1ebe8ff --- /dev/null +++ b/src/components/graph.tsx @@ -0,0 +1,85 @@ +import { ResponsiveLine } from "@nivo/line"; +import { formatBytes } from "../lib/format.js"; + +type Frame = { + id: string; + data: { x: string | number; y: number }[]; +}; + +type GraphProps = { + data: Frame[]; +}; + +const Graph = ({ data }: GraphProps) => ( + formatBytes(v * 1024 * 53), + }} + pointSize={10} + colors={["#3e8faf", "#c4a7e7", "#f5c276", "#EA9B96", "#EB7092", "#9CCFD8"]} + pointBorderWidth={0} + pointBorderColor={{ from: "seriesColor" }} + pointLabelYOffset={-12} + enableSlices={"x"} + enableTouchCrosshair={true} + useMesh={true} + legends={[ + { + anchor: "bottom-right", + direction: "column", + translateX: 100, + itemWidth: 80, + itemHeight: 22, + symbolShape: "circle", + }, + ]} + /> +); + +export default Graph; diff --git a/src/global.css b/src/global.css index 9df2d9b..cfcbf9c 100644 --- a/src/global.css +++ b/src/global.css @@ -37,16 +37,3 @@ body { height: 100vh; text-align: center; } - -#drop-target { - pointer-events: none; - opacity: 0; - background-color: rgb(0, 0, 0, 0.5) !important; -} - -.wails-drop-target-active { - #drop-target { - pointer-events: auto; - opacity: 1; - } -}