From a9394bd73c28eb89a84bc541e281eb33b09a5501 Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Wed, 23 Nov 2022 00:36:28 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B5=8B=E8=AF=95=E7=81=AF=E6=95=88?= =?UTF-8?q?=EF=BC=8C=E6=B5=81=E5=85=89=E6=BA=A2=E5=BD=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + pnpm-lock.yaml | 7 +++++ src-tauri/Cargo.lock | 7 +++++ src-tauri/Cargo.toml | 1 + src-tauri/src/core/core.rs | 51 +++++++++++++++++++++++++++++++ src-tauri/src/core/mod.rs | 3 ++ src-tauri/src/main.rs | 37 ++++++++-------------- src-tauri/src/picker/led_color.rs | 29 +++++++++++++++++- src-tauri/src/rpc/manager.rs | 1 + src-tauri/src/rpc/mqtt.rs | 4 +-- src/App.tsx | 34 +++++++++++++++------ 11 files changed, 139 insertions(+), 36 deletions(-) create mode 100644 src-tauri/src/core/core.rs create mode 100644 src-tauri/src/core/mod.rs diff --git a/package.json b/package.json index 1142b9c..e890a78 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ }, "dependencies": { "@tauri-apps/api": "^1.1.0", + "clsx": "^1.2.1", "react": "^18.2.0", "react-dom": "^18.2.0" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c4aa941..4e5324e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,7 @@ specifiers: '@types/react-dom': ^18.0.6 '@vitejs/plugin-react': ^2.0.0 autoprefixer: ^10.4.13 + clsx: ^1.2.1 eslint-config-prettier: ^8.5.0 eslint-plugin-import: ^2.26.0 eslint-plugin-jsx-a11y: ^6.6.1 @@ -23,6 +24,7 @@ specifiers: dependencies: '@tauri-apps/api': 1.2.0 + clsx: 1.2.1 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 @@ -725,6 +727,11 @@ packages: fsevents: 2.3.2 dev: true + /clsx/1.2.1: + resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==} + engines: {node: '>=6'} + dev: false + /color-convert/1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} dependencies: diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 1d7c27f..6bcf9de 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -306,6 +306,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" +[[package]] +name = "color_space" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3776b2bcc4e914db501bb9be9572dd706e344b9eb8f882894f3daa651d281381" + [[package]] name = "combine" version = "4.6.6" @@ -2458,6 +2464,7 @@ dependencies = [ "anyhow", "base64", "bmp", + "color_space", "hex", "once_cell", "paris", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 52b4fde..861fe39 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -30,6 +30,7 @@ tracing-subscriber = "0.3.16" hex = "0.4.3" rumqttc = "0.17.0" time = { version = "0.3.17", features = ["formatting"] } +color_space = "0.5.3" [features] # by default Tauri runs in production mode diff --git a/src-tauri/src/core/core.rs b/src-tauri/src/core/core.rs new file mode 100644 index 0000000..1b7d92f --- /dev/null +++ b/src-tauri/src/core/core.rs @@ -0,0 +1,51 @@ +use once_cell::sync::OnceCell; +use paris::info; +use std::{sync::Arc, time::Duration}; +use tokio::{sync::Mutex, time::sleep}; +use tracing::warn; + +use crate::{picker::led_color::LedColor, rpc}; + +pub struct CoreManager { + flowing_light_mode: Arc>, +} + +impl CoreManager { + pub fn global() -> &'static CoreManager { + static CORE_MANAGER: OnceCell = OnceCell::new(); + + CORE_MANAGER.get_or_init(|| CoreManager { + flowing_light_mode: Arc::new(Mutex::new(false)), + }) + } + + pub async fn play_flowing_light(&self) { + *self.flowing_light_mode.lock().await = true; + + let mut hue = 0f64; + let step_length = 2.0; + while self.flowing_light_mode.lock().await.to_owned() { + let mut colors = Vec::::new(); + for i in 0..60 { + let color = LedColor::from_hsv((hue + i as f64 * step_length) % 360.0, 1.0, 0.5); + colors.push(color); + } + hue = (hue + 1.0) % 360.0; + match rpc::manager::Manager::global() + .publish_led_colors(&colors) + .await + { + Ok(_) => {} + Err(error) => { + warn!("publish led colors failed. {}", error); + } + } + sleep(Duration::from_millis(10)).await; + } + } + + pub async fn stop_flowing_light(&self) { + let mut mode = self.flowing_light_mode.lock().await; + *mode = false; + } +} diff --git a/src-tauri/src/core/mod.rs b/src-tauri/src/core/mod.rs new file mode 100644 index 0000000..e559917 --- /dev/null +++ b/src-tauri/src/core/mod.rs @@ -0,0 +1,3 @@ +mod core; + +pub use self::core::*; \ No newline at end of file diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 4992cd1..05fcefb 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -3,15 +3,15 @@ windows_subsystem = "windows" )] +mod core; mod picker; mod rpc; use paris::*; use picker::led_color::LedColor; use picker::manager::Picker; -use std::{ - time::Instant, -}; +use crate::core::CoreManager; +use std::time::Instant; #[tauri::command] async fn refresh_displays() { @@ -59,26 +59,13 @@ async fn get_led_strip_colors() -> Result, String> { } } -async fn bitmap_to_webp_base64(width: usize, height: usize, bitmap: Vec) -> String { - let mut bitflipped = Vec::with_capacity(width * height * 3); - let stride = bitmap.len() / height; - - // let mut img = Image::new(w as u32, h as u32); - for y in 0..height { - for x in 0..width { - let i = stride * y + 4 * x; - bitflipped.extend_from_slice(&[bitmap[i + 2], bitmap[i + 1], bitmap[i]]); - // img.set_pixel( - // x as u32, - // y as u32, - // Pixel::new(buffer[i + 2], buffer[i + 1], buffer[i]), - // ); - } - } - - let webp_memory = - webp::Encoder::from_rgb(bitflipped.as_slice(), width as u32, height as u32).encode(100.0); - return base64::encode(&*webp_memory); +#[tauri::command] +async fn play_flowing_light() { + CoreManager::global().play_flowing_light().await; +} +#[tauri::command] +async fn stop_flowing_light() { + CoreManager::global().stop_flowing_light().await; } #[tokio::main] @@ -88,7 +75,9 @@ async fn main() { .invoke_handler(tauri::generate_handler![ take_snapshot, refresh_displays, - get_led_strip_colors + get_led_strip_colors, + play_flowing_light, + stop_flowing_light, ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/src-tauri/src/picker/led_color.rs b/src-tauri/src/picker/led_color.rs index 5a4b280..9cf6224 100644 --- a/src-tauri/src/picker/led_color.rs +++ b/src-tauri/src/picker/led_color.rs @@ -1,3 +1,4 @@ +use color_space::{Hsv, Rgb}; use paris::info; use serde::Serialize; @@ -15,6 +16,33 @@ impl LedColor { Self { bits: [r, g, b] } } + pub fn from_hsv(h: f64, s: f64, v: f64) -> Self { + let rgb = Rgb::from(Hsv::new(h, s, v)); + // let h = h % 360; + // let rgb_max = v * 255.0; + // let rgb_min = rgb_max * (1.0 - s as f32); + // let i = h / 60; + // let diff = h % 60; + + // let rgb_adj = (rgb_max - rgb_min) * diff as f32 / 60.0; + + // let bits: [u8; 3] = if i == 0 { + // [rgb_max as u8, (rgb_min + rgb_adj) as u8, rgb_min as u8] + // } else if i == 1 { + // [(rgb_max - rgb_adj) as u8, rgb_max as u8, rgb_min as u8] + // } else if i == 2 { + // [rgb_min as u8, rgb_max as u8, (rgb_min + rgb_adj) as u8] + // } else if i == 3 { + // [rgb_min as u8, (rgb_max - rgb_adj) as u8, rgb_max as u8] + // } else if i == 4 { + // [(rgb_min + rgb_adj) as u8, rgb_min as u8, rgb_max as u8] + // } else { + // [rgb_max as u8, rgb_min as u8, (rgb_max - rgb_adj) as u8] + // }; + + Self { bits: [rgb.r as u8, rgb.g as u8, rgb.b as u8] } + } + pub fn get_rgb(&self) -> [u8; 3] { self.bits } @@ -43,7 +71,6 @@ impl Serialize for LedColor { where S: serde::Serializer, { - info!("{:?}", self.bits); let hex = format!("#{}", hex::encode(self.bits)); serializer.serialize_str(hex.as_str()) } diff --git a/src-tauri/src/rpc/manager.rs b/src-tauri/src/rpc/manager.rs index 977e41e..b6a3af6 100644 --- a/src-tauri/src/rpc/manager.rs +++ b/src-tauri/src/rpc/manager.rs @@ -2,6 +2,7 @@ use crate::picker::led_color::LedColor; use super::mqtt::MqttConnection; use once_cell::sync::OnceCell; +use paris::info; pub struct Manager { mqtt: MqttConnection, diff --git a/src-tauri/src/rpc/mqtt.rs b/src-tauri/src/rpc/mqtt.rs index 5c40a3d..6b9de20 100644 --- a/src-tauri/src/rpc/mqtt.rs +++ b/src-tauri/src/rpc/mqtt.rs @@ -27,9 +27,9 @@ impl MqttConnection { self.broadcast_desktop_online(); } - fn subscribe_board(&self) { + async fn subscribe_board(&self) { self.client - .subscribe("screen-bg-light/board/#", QoS::AtMostOnce); + .subscribe("screen-bg-light/board/#", QoS::AtMostOnce).await; } fn broadcast_desktop_online(&mut self) { diff --git a/src/App.tsx b/src/App.tsx index 89bd56e..30cd177 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -2,12 +2,14 @@ import { useCallback, useState } from 'react'; import reactLogo from './assets/react.svg'; import { invoke } from '@tauri-apps/api/tauri'; import './App.css'; +import clsx from 'clsx'; function App() { const [greetMsg, setGreetMsg] = useState(''); const [name, setName] = useState(''); const [screenshots, setScreenshots] = useState([]); const [ledStripColors, setLedStripColors] = useState([]); + const [flowingLightMode, setFlowingLightMode] = useState(false); async function greet() { // Learn more about Tauri commands at https://tauri.app/v1/guides/features/command @@ -28,6 +30,17 @@ function App() { setLedStripColors(await invoke('get_led_strip_colors')); }, []); + const switchFlowingLightMode = useCallback(async () => { + console.log('A', flowingLightMode); + if (flowingLightMode) { + await invoke('stop_flowing_light'); + } else { + invoke('play_flowing_light'); + } + console.log('B', flowingLightMode); + setFlowingLightMode(!flowingLightMode); + }, [flowingLightMode]); + return (
@@ -66,18 +79,21 @@ function App() { > Get Colors +
- - Vite logo - - - Tauri logo - - - React logo - + Vite logo + Tauri logo + React logo
);