diff --git a/desktop/package-lock.json b/desktop/package-lock.json index 96deb12..a8f9351 100644 --- a/desktop/package-lock.json +++ b/desktop/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@tauri-apps/api": "^1.4.0", "peerjs": "^1.5.1", + "qr-code-styling": "^1.6.0-rc.1", "react": "^18.2.0", "react-dom": "^18.2.0" }, @@ -19,6 +20,7 @@ "@types/react-dom": "^18.2.7", "@vitejs/plugin-react": "^4.0.3", "autoprefixer": "^10.4.16", + "daisyui": "^4.4.2", "postcss": "^8.4.31", "tailwindcss": "^3.3.5", "typescript": "^5.0.2", @@ -1476,6 +1478,16 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, + "node_modules/css-selector-tokenizer": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.8.0.tgz", + "integrity": "sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "fastparse": "^1.1.2" + } + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -1494,6 +1506,34 @@ "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", "dev": true }, + "node_modules/culori": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/culori/-/culori-3.2.0.tgz", + "integrity": "sha512-HIEbTSP7vs1mPq/2P9In6QyFE0Tkpevh0k9a+FkjhD+cwsYm9WRSbn4uMdW9O0yXlNYC3ppxL3gWWPOcvEl57w==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/daisyui": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-4.4.2.tgz", + "integrity": "sha512-Ecg5loskj9dkaAnTSK5Xn5jb24TqDlQIg/NJ025jCkw2S/zw12btjvLgY2Sv5Ws1DFVoVBRs3XYXyojZG7zVnw==", + "dev": true, + "dependencies": { + "css-selector-tokenizer": "^0.8", + "culori": "^3", + "picocolors": "^1", + "postcss-js": "^4" + }, + "engines": { + "node": ">=16.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/daisyui" + } + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -1617,6 +1657,12 @@ "node": ">= 6" } }, + "node_modules/fastparse": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", + "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==", + "dev": true + }, "node_modules/fastq": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", @@ -2238,6 +2284,19 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "dev": true }, + "node_modules/qr-code-styling": { + "version": "1.6.0-rc.1", + "resolved": "https://registry.npmjs.org/qr-code-styling/-/qr-code-styling-1.6.0-rc.1.tgz", + "integrity": "sha512-ModRIiW6oUnsP18QzrRYZSc/CFKFKIdj7pUs57AEVH20ajlglRpN3HukjHk0UbNMTlKGuaYl7Gt6/O5Gg2NU2Q==", + "dependencies": { + "qrcode-generator": "^1.4.3" + } + }, + "node_modules/qrcode-generator": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/qrcode-generator/-/qrcode-generator-1.4.4.tgz", + "integrity": "sha512-HM7yY8O2ilqhmULxGMpcHSF1EhJJ9yBj8gvDEuZ6M+KGJ0YY2hKpnXvRD+hZPLrDVck3ExIGhmPtSdcjC+guuw==" + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", diff --git a/desktop/package.json b/desktop/package.json index 6a58e61..726eac1 100644 --- a/desktop/package.json +++ b/desktop/package.json @@ -12,6 +12,7 @@ "dependencies": { "@tauri-apps/api": "^1.4.0", "peerjs": "^1.5.1", + "qr-code-styling": "^1.6.0-rc.1", "react": "^18.2.0", "react-dom": "^18.2.0" }, @@ -21,6 +22,7 @@ "@types/react-dom": "^18.2.7", "@vitejs/plugin-react": "^4.0.3", "autoprefixer": "^10.4.16", + "daisyui": "^4.4.2", "postcss": "^8.4.31", "tailwindcss": "^3.3.5", "typescript": "^5.0.2", diff --git a/desktop/src-tauri/Cargo.lock b/desktop/src-tauri/Cargo.lock index fe123c6..4f60bbe 100644 --- a/desktop/src-tauri/Cargo.lock +++ b/desktop/src-tauri/Cargo.lock @@ -642,6 +642,8 @@ dependencies = [ "libc", "objc", "pkg-config", + "serde", + "serde_derive", "windows 0.51.1", ] diff --git a/desktop/src-tauri/Cargo.toml b/desktop/src-tauri/Cargo.toml index d04f31a..59b6ad6 100644 --- a/desktop/src-tauri/Cargo.toml +++ b/desktop/src-tauri/Cargo.toml @@ -16,7 +16,7 @@ tauri-build = { version = "1.4", features = [] } tauri = { version = "1.4", features = ["shell-open"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -enigo = "0.1.3" +enigo = { version = "0.1.3", features = ["serde_derive", "serde", "with_serde"] } [features] # this feature is used for production builds or when `devPath` points to the filesystem diff --git a/desktop/src-tauri/src/main.rs b/desktop/src-tauri/src/main.rs index 523550d..6e54b83 100644 --- a/desktop/src-tauri/src/main.rs +++ b/desktop/src-tauri/src/main.rs @@ -1,15 +1,39 @@ // Prevents additional console window on Windows in release, DO NOT REMOVE!! #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] +use enigo::*; +use std::sync::Mutex; +use tauri::State; + // Learn more about Tauri commands at https://tauri.app/v1/guides/features/command #[tauri::command] fn greet(name: &str) -> String { format!("Hello, {}! You've been greeted from Rust!", name) } +struct Controller(Mutex); + +#[tauri::command] +fn press(controller: State<'_, Controller>, key: &str) { + let mut controller = (&controller.0).lock().unwrap(); + match key { + "VOL_UP" => { + controller.key_down(Key::VolumeUp); + }, + "VOL_DN" => { + controller.key_down(Key::VolumeDown); + }, + _ => {} + } +} + + fn main() { + let controller = Enigo::new(); + tauri::Builder::default() - .invoke_handler(tauri::generate_handler![greet]) + .manage(Controller(Mutex::new(controller))) + .invoke_handler(tauri::generate_handler![press]) .run(tauri::generate_context!()) .expect("error while running tauri application"); } diff --git a/desktop/src/App.tsx b/desktop/src/App.tsx index e6b5a34..a5ed11c 100644 --- a/desktop/src/App.tsx +++ b/desktop/src/App.tsx @@ -1,21 +1,84 @@ -import { useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { invoke } from "@tauri-apps/api/tauri"; -import { Peer } from "peerjs"; +import { DataConnection, Peer } from "peerjs"; +import QRCodeStyling from "qr-code-styling"; +import { createQR } from "./qr"; +import { BASE_URL } from "./config"; -import "./App.css"; +const qrCode = new QRCodeStyling({ + width: 300, + height: 300, + image: + "https://upload.wikimedia.org/wikipedia/commons/5/51/Facebook_f_logo_%282019%29.svg", + dotsOptions: { + color: "#4267b2", + type: "rounded" + }, + imageOptions: { + crossOrigin: "anonymous", + margin: 20 + } +}); + +enum Action { + VOL_UP, + VOL_DN +} +interface Message { + action: Action +} function App() { - const [greetMsg, setGreetMsg] = useState(""); + const [peer, setPeer] = useState(new Peer()); + const [id, setId] = useState('') + const [conn, setConn] = useState(null) const [name, setName] = useState(""); + const qrDiv = useRef() + + + function onMessage(message: unknown) { + const data = JSON.parse(message as string) as Message + switch (data.action) { + case Action.VOL_UP: { + invoke('press', {key: 'VOL_UP'}) + break; + } + case Action.VOL_DN: { + invoke('press', {key: 'VOL_DN'}) + break; + } + } + } + + useEffect(() => { + conn?.on('data', onMessage) + }, [conn]) + - async function greet() { - // Learn more about Tauri commands at https://tauri.app/v1/guides/features/command - setGreetMsg(await invoke("greet", { name })); + + function onConnect(connection: DataConnection) { + + setConn(connection) } + + useEffect(() => { + peer.on('open', id => { + setId(id) + console.log('creating qr') + const qr = createQR(`${BASE_URL}?id=${id}`) + qr.append(qrDiv.current) + }) + peer.on('connection', onConnect) + }, []) + + + return (
- +
address is {id}
+
connection is from {conn?.connectionId}
+
); } diff --git a/desktop/src/config.ts b/desktop/src/config.ts new file mode 100644 index 0000000..28588f3 --- /dev/null +++ b/desktop/src/config.ts @@ -0,0 +1 @@ +export const BASE_URL = 'https://thewh1teagle.github.io/mobslide/' \ No newline at end of file diff --git a/desktop/src/main.tsx b/desktop/src/main.tsx index 2d15992..fba88e5 100644 --- a/desktop/src/main.tsx +++ b/desktop/src/main.tsx @@ -4,7 +4,5 @@ import App from "./App"; import "./main.css"; ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( - - , ); diff --git a/desktop/src/qr.ts b/desktop/src/qr.ts new file mode 100644 index 0000000..848d26d --- /dev/null +++ b/desktop/src/qr.ts @@ -0,0 +1,37 @@ +import QRCodeStyling, {Options} from "qr-code-styling"; + +const options: Options = { + width: 300, + height: 300, + data: "", + margin: 0, + qrOptions: { + + mode: "Byte", + errorCorrectionLevel: "Q" + }, + imageOptions: { + hideBackgroundDots: true, + imageSize: 0.4, + margin: 0 + }, + dotsOptions: { + type: "extra-rounded", + color: "#2786ec" + }, + backgroundOptions: { + color: "#ffffff" + }, + cornersSquareOptions: { + type: "extra-rounded", + color: "#595959" + }, + cornersDotOptions: { + type: "square", + color: "#595959" + }, + } + + export function createQR(data: string) { + return new QRCodeStyling({...options, data}) + } \ No newline at end of file diff --git a/desktop/tailwind.config.js b/desktop/tailwind.config.js index d37737f..e1a3afb 100644 --- a/desktop/tailwind.config.js +++ b/desktop/tailwind.config.js @@ -1,3 +1,5 @@ +import daisyui from 'daisyui' + /** @type {import('tailwindcss').Config} */ export default { content: [ @@ -7,6 +9,6 @@ export default { theme: { extend: {}, }, - plugins: [], + plugins: [daisyui], } diff --git a/web/package-lock.json b/web/package-lock.json index c3ad1b4..7ac8769 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -19,6 +19,7 @@ "@typescript-eslint/parser": "^6.10.0", "@vitejs/plugin-react-swc": "^3.5.0", "autoprefixer": "^10.4.16", + "daisyui": "^4.4.2", "eslint": "^8.53.0", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.4", @@ -1646,6 +1647,16 @@ "node": ">= 8" } }, + "node_modules/css-selector-tokenizer": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.8.0.tgz", + "integrity": "sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "fastparse": "^1.1.2" + } + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -1664,6 +1675,34 @@ "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", "dev": true }, + "node_modules/culori": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/culori/-/culori-3.2.0.tgz", + "integrity": "sha512-HIEbTSP7vs1mPq/2P9In6QyFE0Tkpevh0k9a+FkjhD+cwsYm9WRSbn4uMdW9O0yXlNYC3ppxL3gWWPOcvEl57w==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/daisyui": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-4.4.2.tgz", + "integrity": "sha512-Ecg5loskj9dkaAnTSK5Xn5jb24TqDlQIg/NJ025jCkw2S/zw12btjvLgY2Sv5Ws1DFVoVBRs3XYXyojZG7zVnw==", + "dev": true, + "dependencies": { + "css-selector-tokenizer": "^0.8", + "culori": "^3", + "picocolors": "^1", + "postcss-js": "^4" + }, + "engines": { + "node": ">=16.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/daisyui" + } + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -2001,6 +2040,12 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "node_modules/fastparse": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", + "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==", + "dev": true + }, "node_modules/fastq": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", diff --git a/web/package.json b/web/package.json index 707de91..0dbc670 100644 --- a/web/package.json +++ b/web/package.json @@ -21,6 +21,7 @@ "@typescript-eslint/parser": "^6.10.0", "@vitejs/plugin-react-swc": "^3.5.0", "autoprefixer": "^10.4.16", + "daisyui": "^4.4.2", "eslint": "^8.53.0", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.4", diff --git a/web/src/App.tsx b/web/src/App.tsx index dde37c8..ba8c811 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -1,32 +1,48 @@ -import { useState } from 'react' -import reactLogo from './assets/react.svg' -import viteLogo from '/vite.svg' +import Peer, { DataConnection } from 'peerjs'; +import { useEffect, useState } from 'react'; + +enum Action { + VOL_UP, + VOL_DN +} +interface Message { + action: Action +} + + +// 8e25320d-7759-469e-b019-035b48593438 function App() { - const [count, setCount] = useState(0) + const params = new URLSearchParams(window.location.search); + + const [peer, setPeer] = useState(new Peer()); + const [conn, setConn] = useState(null) + + function sendMessage(data: Message) { + conn?.send(JSON.stringify(data)) + } + + + useEffect(() => { + const address = params.get('id') + console.log('connecting to ', address) + peer.on('open', () => { + const connection = peer.connect(address!) + setConn(connection) + }) + + + }, []) return ( <> - -

Vite + React

-
- -

- Edit src/App.tsx and save to test HMR -

-
-

- Click on the Vite and React logos to learn more -

+
connected to {conn?.connectionId}
+ + ) } diff --git a/web/tailwind.config.js b/web/tailwind.config.js index d37737f..e1a3afb 100644 --- a/web/tailwind.config.js +++ b/web/tailwind.config.js @@ -1,3 +1,5 @@ +import daisyui from 'daisyui' + /** @type {import('tailwindcss').Config} */ export default { content: [ @@ -7,6 +9,6 @@ export default { theme: { extend: {}, }, - plugins: [], + plugins: [daisyui], }