From 56edd8ac771a144559b66c5d9a6af8cd5f59e33c Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Thu, 24 Nov 2022 23:21:46 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=81=AF=E5=85=89=E8=B7=9F=E9=9A=8F?= =?UTF-8?q?=E5=B1=8F=E5=B9=95=E5=86=85=E5=AE=B9=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat: 灯光跟随屏幕内容。 --- src-tauri/src/core/core.rs | 124 +++++++++++++++++++++++------ src-tauri/src/main.rs | 16 ++-- src-tauri/src/picker/led_color.rs | 23 ------ src-tauri/src/picker/screenshot.rs | 7 +- src-tauri/src/rpc/manager.rs | 1 - src-tauri/src/rpc/mqtt.rs | 4 +- src/App.tsx | 48 ++++++----- 7 files changed, 139 insertions(+), 84 deletions(-) diff --git a/src-tauri/src/core/core.rs b/src-tauri/src/core/core.rs index 1b7d92f..237bf0c 100644 --- a/src-tauri/src/core/core.rs +++ b/src-tauri/src/core/core.rs @@ -1,51 +1,125 @@ use once_cell::sync::OnceCell; use paris::info; +use serde::{Deserialize, Serialize}; use std::{sync::Arc, time::Duration}; +use tauri::async_runtime::RwLock; use tokio::{sync::Mutex, time::sleep}; use tracing::warn; -use crate::{picker::led_color::LedColor, rpc}; +use crate::{ + picker::{led_color::LedColor, manager::Picker}, + rpc, +}; + +#[derive(Debug, Serialize, Deserialize)] +pub enum AmbientLightMode { + None, + Follow, + Flowing, +} pub struct CoreManager { - flowing_light_mode: Arc>, + ambient_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)), - }) + let core = CORE_MANAGER.get_or_init(|| CoreManager { + ambient_light_mode: Arc::new(RwLock::new(AmbientLightMode::None)), + }); + + tokio::spawn(async { + loop { + core.play_flowing_light().await; + match core.play_follow().await { + Ok(_) => {} + Err(error) => { + warn!("Can not following displays. {}", error); + sleep(Duration::from_millis(1000)).await; + } + }; + sleep(Duration::from_millis(10)).await; + } + }); + core + } + + pub async fn set_ambient_light(&self, target_mode: AmbientLightMode) { + let mut mode = self.ambient_light_mode.write().await; + *mode = target_mode; } 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); + loop { + let lock = self.ambient_light_mode.read().await; + if let AmbientLightMode::Flowing = *lock { + 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); + } + } + } else { + break; } - sleep(Duration::from_millis(10)).await; + sleep(Duration::from_millis(50)).await; } } - pub async fn stop_flowing_light(&self) { - let mut mode = self.flowing_light_mode.lock().await; - *mode = false; + pub async fn play_follow(&self) -> anyhow::Result<()> { + { + info!("Following A"); + let lock = self.ambient_light_mode.read().await; + if let AmbientLightMode::Follow = *lock { + Picker::global().refresh_displays().await?; + info!("Following B"); + } else { + return Ok(()); + } + } + + loop { + info!("Following"); + let lock = self.ambient_light_mode.read().await; + if let AmbientLightMode::Follow = *lock { + match Picker::global().take_screenshots_for_all().await { + Ok(_) => { + let colors = Picker::global().get_led_strip_colors().await; + match colors { + Ok(colors) => { + let colors = colors.into_iter().rev().collect(); + rpc::manager::Manager::global() + .publish_led_colors(&colors) + .await; + } + Err(error) => { + warn!("get strip colors failed. {}", error); + } + } + } + Err(error) => { + warn!("take screenshots failed. {}", error); + } + } + } else { + break; + } + } + + Ok(()) } } diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 8d67752..5bec1cb 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -7,10 +7,11 @@ mod core; mod picker; mod rpc; +use crate::core::CoreManager; +use crate::core::AmbientLightMode; use paris::*; use picker::led_color::LedColor; use picker::manager::Picker; -use crate::core::CoreManager; use std::time::Instant; #[tauri::command] @@ -60,12 +61,10 @@ async fn get_led_strip_colors() -> Result, String> { } #[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; +async fn play_mode(target_mode: AmbientLightMode) { + info!("target mode: {:?}", target_mode); + + CoreManager::global().set_ambient_light(target_mode).await; } #[tokio::main] @@ -76,8 +75,7 @@ async fn main() { take_snapshot, refresh_displays, get_led_strip_colors, - play_flowing_light, - stop_flowing_light, + play_mode, ]) .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 9cf6224..073c841 100644 --- a/src-tauri/src/picker/led_color.rs +++ b/src-tauri/src/picker/led_color.rs @@ -1,5 +1,4 @@ use color_space::{Hsv, Rgb}; -use paris::info; use serde::Serialize; #[derive(Clone, Copy)] @@ -18,28 +17,6 @@ impl LedColor { 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] } } diff --git a/src-tauri/src/picker/screenshot.rs b/src-tauri/src/picker/screenshot.rs index 905fb81..4b76c45 100644 --- a/src-tauri/src/picker/screenshot.rs +++ b/src-tauri/src/picker/screenshot.rs @@ -81,12 +81,11 @@ impl Screenshot { b / cell_size as f64, ); let hsv = Hsv::from(rgb); - info!("HSV: {:?}", [hsv.h, hsv.s, hsv.v]); - let color = LedColor::from_hsv(hsv.h, hsv.s * 10.0, hsv.v / 2.0); - info!("color: {:?}", color.get_rgb()); + // info!("HSV: {:?}", [hsv.h, hsv.s, hsv.v]); + let color = LedColor::from_hsv(hsv.h, hsv.s, hsv.v); + // info!("color: {:?}", color.get_rgb()); colors.push(color); } - colors.reverse(); return Ok(colors); } None => Ok(vec![]), diff --git a/src-tauri/src/rpc/manager.rs b/src-tauri/src/rpc/manager.rs index d00d0fd..6166ae7 100644 --- a/src-tauri/src/rpc/manager.rs +++ b/src-tauri/src/rpc/manager.rs @@ -2,7 +2,6 @@ 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 9adfe5a..6be8f9b 100644 --- a/src-tauri/src/rpc/mqtt.rs +++ b/src-tauri/src/rpc/mqtt.rs @@ -13,10 +13,10 @@ impl MqttConnection { let mut options = MqttOptions::new("rumqtt-async", "192.168.31.11", 1883); options.set_keep_alive(Duration::from_secs(5)); - let (mut client, mut eventloop) = AsyncClient::new(options, 10); + let (client, mut eventloop) = AsyncClient::new(options, 10); task::spawn(async move { while let Ok(notification) = eventloop.poll().await { - println!("Received = {:?}", notification); + // println!("Received = {:?}", notification); } }); Self { client } diff --git a/src/App.tsx b/src/App.tsx index 30cd177..4c6ecde 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -4,17 +4,12 @@ import { invoke } from '@tauri-apps/api/tauri'; import './App.css'; import clsx from 'clsx'; +type Mode = 'Flowing' | 'Follow' | null; + 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 - setGreetMsg(await invoke('greet', { name })); - } + const [currentMode, setCurrentMode] = useState(null); async function takeSnapshot() { const base64TextList: string[] = await invoke('take_snapshot'); @@ -30,16 +25,20 @@ 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]); + const switchCurrentMode = useCallback( + async (targetMode: Mode) => { + console.log(targetMode, currentMode, currentMode === targetMode); + if (currentMode === targetMode) { + await invoke('play_mode', { targetMode: 'None' }); + setCurrentMode(null); + } else { + await invoke('play_mode', { targetMode }); + setCurrentMode(targetMode); + } + console.log(targetMode, currentMode, currentMode === targetMode); + }, + [currentMode, setCurrentMode], + ); return (
@@ -81,13 +80,22 @@ function App() { +