feature/gui-configuration:支持从 GUI 配置程序。 #4
@ -95,7 +95,7 @@ impl CoreManager {
|
|||||||
let mut futs = vec![];
|
let mut futs = vec![];
|
||||||
if let AmbientLightMode::Follow = *lock {
|
if let AmbientLightMode::Follow = *lock {
|
||||||
drop(lock);
|
drop(lock);
|
||||||
let configs = Picker::global().display_configs.lock().await;
|
let configs = Picker::global().await.display_configs.lock().await;
|
||||||
|
|
||||||
let (tx, mut rx) = mpsc::channel(10);
|
let (tx, mut rx) = mpsc::channel(10);
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ use std::vec;
|
|||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
async fn take_snapshot() -> Vec<ScreenshotDto> {
|
async fn take_snapshot() -> Vec<ScreenshotDto> {
|
||||||
let manager = Picker::global();
|
let manager = Picker::global().await;
|
||||||
|
|
||||||
let start = time::Instant::now();
|
let start = time::Instant::now();
|
||||||
let base64_bitmap_list = match manager.list_displays().await {
|
let base64_bitmap_list = match manager.list_displays().await {
|
||||||
@ -42,12 +42,10 @@ async fn get_screenshot_by_config(config: DisplayConfig) -> Result<ScreenshotDto
|
|||||||
let manager = Picker::global();
|
let manager = Picker::global();
|
||||||
|
|
||||||
let start = time::Instant::now();
|
let start = time::Instant::now();
|
||||||
let screenshot_dto = manager.get_screenshot_by_config(config).await;
|
let screenshot_dto = manager.await.get_screenshot_by_config(config).await;
|
||||||
info!("截图耗时 {} s", start.elapsed().as_seconds_f32());
|
info!("截图耗时 {} s", start.elapsed().as_seconds_f32());
|
||||||
match screenshot_dto {
|
match screenshot_dto {
|
||||||
Ok(screenshot_dto) => {
|
Ok(screenshot_dto) => Ok(screenshot_dto),
|
||||||
Ok(screenshot_dto)
|
|
||||||
}
|
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
error!("get_screenshot_by_config failed. {}", error);
|
error!("get_screenshot_by_config failed. {}", error);
|
||||||
Err(format!("get_screenshot_by_config failed. {}", error))
|
Err(format!("get_screenshot_by_config failed. {}", error))
|
||||||
@ -56,11 +54,25 @@ async fn get_screenshot_by_config(config: DisplayConfig) -> Result<ScreenshotDto
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
fn get_picker_config() -> picker::config::Configuration {
|
async fn get_picker_config() -> picker::config::Configuration {
|
||||||
let configuration = picker::config::Manager::global().get_config();
|
let configuration = picker::config::Manager::global().get_config().await;
|
||||||
info!("configuration: {:?}", configuration);
|
info!("configuration: {:?}", configuration);
|
||||||
configuration
|
configuration
|
||||||
}
|
}
|
||||||
|
#[tauri::command]
|
||||||
|
async fn write_picker_config(config: picker::config::Configuration) -> Result<(), String> {
|
||||||
|
let manager = picker::config::Manager::global();
|
||||||
|
let path = picker::config::Manager::get_config_file_path();
|
||||||
|
info!("log save in {:?}", path.to_str());
|
||||||
|
manager.set_config(&config).await;
|
||||||
|
match picker::config::Manager::write_config_to_disk(path, &config) {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(err) => {
|
||||||
|
error!("can not write picker config. {:?}", err);
|
||||||
|
Err(format!("can not write picker config. {:?}", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
async fn play_mode(target_mode: AmbientLightMode) {
|
async fn play_mode(target_mode: AmbientLightMode) {
|
||||||
@ -78,6 +90,7 @@ async fn main() {
|
|||||||
play_mode,
|
play_mode,
|
||||||
get_picker_config,
|
get_picker_config,
|
||||||
get_screenshot_by_config,
|
get_screenshot_by_config,
|
||||||
|
write_picker_config,
|
||||||
])
|
])
|
||||||
.run(tauri::generate_context!())
|
.run(tauri::generate_context!())
|
||||||
.expect("error while running tauri application");
|
.expect("error while running tauri application");
|
||||||
|
@ -2,12 +2,13 @@ use std::{
|
|||||||
env::current_dir,
|
env::current_dir,
|
||||||
fs::{self, File},
|
fs::{self, File},
|
||||||
io::Read,
|
io::Read,
|
||||||
path::PathBuf,
|
path::PathBuf, sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
|
use paris::info;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tauri::api::path::config_dir;
|
use tauri::{api::path::config_dir, async_runtime::Mutex};
|
||||||
|
|
||||||
use super::DisplayConfig;
|
use super::DisplayConfig;
|
||||||
|
|
||||||
@ -26,9 +27,8 @@ impl Configuration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
pub struct Manager {
|
pub struct Manager {
|
||||||
config: Configuration,
|
config: Arc<Mutex<Configuration>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Manager {
|
impl Manager {
|
||||||
@ -43,7 +43,7 @@ impl Manager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(config: Configuration) -> Self {
|
pub fn new(config: Configuration) -> Self {
|
||||||
Self { config }
|
Self { config: Arc::new(Mutex::new(config)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_config_file_path() -> PathBuf {
|
pub fn get_config_file_path() -> PathBuf {
|
||||||
@ -70,16 +70,21 @@ impl Manager {
|
|||||||
.map_err(|error| anyhow::anyhow!("can not parse config file contents. {}", error))
|
.map_err(|error| anyhow::anyhow!("can not parse config file contents. {}", error))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_config_to_disk(&self, config_file_path: PathBuf) -> anyhow::Result<()> {
|
pub fn write_config_to_disk(config_file_path: PathBuf, config: &Configuration) -> anyhow::Result<()> {
|
||||||
let contents = serde_json::to_string(&self.config)
|
let contents = serde_json::to_string(config)
|
||||||
.map_err(|error| anyhow::anyhow!("can not serialize config. {}", error))?;
|
.map_err(|error| anyhow::anyhow!("can not serialize config. {}", error))?;
|
||||||
|
info!("contents: {}", contents);
|
||||||
fs::write(config_file_path, contents.as_bytes())
|
fs::write(config_file_path, contents.as_bytes())
|
||||||
.map_err(|error| anyhow::anyhow!("can not write config file. {}", error))?;
|
.map_err(|error| anyhow::anyhow!("can not write config file. {}", error))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_config(&self) -> Configuration {
|
pub async fn get_config(&self) -> Configuration {
|
||||||
self.config.clone()
|
self.config.lock().await.clone()
|
||||||
|
}
|
||||||
|
pub async fn set_config(&self, new_config: &Configuration) {
|
||||||
|
let mut config = self.config.lock().await;
|
||||||
|
*config = new_config.clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,13 +98,13 @@ mod tests {
|
|||||||
|
|
||||||
use crate::picker::config::Configuration;
|
use crate::picker::config::Configuration;
|
||||||
|
|
||||||
#[test]
|
#[tokio::test]
|
||||||
fn write_config_to_disk_should_be_successful() {
|
async fn write_config_to_disk_should_be_successful() {
|
||||||
let temp = TestDir::temp().create("config_dir", test_dir::FileType::Dir);
|
let temp = TestDir::temp().create("config_dir", test_dir::FileType::Dir);
|
||||||
let config_file_path = temp.path("config_dir").join("picker.config.json");
|
let config_file_path = temp.path("config_dir").join("picker.config.json");
|
||||||
let manager = crate::picker::config::manger::Manager::default();
|
let manager = crate::picker::config::manger::Manager::default();
|
||||||
manager
|
crate::picker::config::manger::Manager
|
||||||
.write_config_to_disk(config_file_path.clone())
|
::write_config_to_disk(config_file_path.clone(), &Configuration::default())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let contents = fs::read_to_string(config_file_path.clone()).unwrap();
|
let contents = fs::read_to_string(config_file_path.clone()).unwrap();
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
use futures::{stream::FuturesUnordered, StreamExt};
|
use futures::{stream::FuturesUnordered, StreamExt};
|
||||||
use once_cell::sync::OnceCell;
|
|
||||||
use paris::info;
|
use paris::info;
|
||||||
use scrap::Display;
|
use scrap::Display;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::{sync::Mutex, task};
|
use tokio::{
|
||||||
|
sync::{Mutex, OnceCell},
|
||||||
|
task,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::picker::{config, screen::Screen};
|
use crate::picker::{config, screen::Screen};
|
||||||
|
|
||||||
@ -20,16 +22,20 @@ pub struct Picker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Picker {
|
impl Picker {
|
||||||
pub fn global() -> &'static Picker {
|
pub async fn global() -> &'static Picker {
|
||||||
static SCREEN_COLOR_PICKER: OnceCell<Picker> = OnceCell::new();
|
static SCREEN_COLOR_PICKER: OnceCell<Picker> = OnceCell::const_new();
|
||||||
|
|
||||||
SCREEN_COLOR_PICKER.get_or_init(|| Picker {
|
SCREEN_COLOR_PICKER
|
||||||
screens: Arc::new(Mutex::new(vec![])),
|
.get_or_init(|| async {
|
||||||
screenshots: Arc::new(Mutex::new(vec![])),
|
Picker {
|
||||||
display_configs: Arc::new(Mutex::new(
|
screens: Arc::new(Mutex::new(vec![])),
|
||||||
config::Manager::global().get_config().display_configs,
|
screenshots: Arc::new(Mutex::new(vec![])),
|
||||||
)),
|
display_configs: Arc::new(Mutex::new(
|
||||||
})
|
config::Manager::global().get_config().await.display_configs,
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn list_displays(&self) -> anyhow::Result<Vec<ScreenshotDto>> {
|
pub async fn list_displays(&self) -> anyhow::Result<Vec<ScreenshotDto>> {
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
"icons/icon.icns",
|
"icons/icon.icns",
|
||||||
"icons/icon.ico"
|
"icons/icon.ico"
|
||||||
],
|
],
|
||||||
"identifier": "com.tauri.dev",
|
"identifier": "cc.ivanli.ambient",
|
||||||
"longDescription": "",
|
"longDescription": "",
|
||||||
"macOS": {
|
"macOS": {
|
||||||
"entitlements": null,
|
"entitlements": null,
|
||||||
|
@ -22,6 +22,11 @@ const getScreenshotByConfig = async (config: DisplayConfig) => {
|
|||||||
config,
|
config,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
const writePickerConfig = async (config: PickerConfiguration) => {
|
||||||
|
return await invoke<void>('write_picker_config', {
|
||||||
|
config,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const Configurator: FC = () => {
|
export const Configurator: FC = () => {
|
||||||
const { loading: pendingPickerConfig, result: savedPickerConfig } = useAsync(
|
const { loading: pendingPickerConfig, result: savedPickerConfig } = useAsync(
|
||||||
@ -34,14 +39,25 @@ export const Configurator: FC = () => {
|
|||||||
|
|
||||||
const [screenshotOfDisplays, setScreenshotOfDisplays] = useState<ScreenshotDto[]>([]);
|
const [screenshotOfDisplays, setScreenshotOfDisplays] = useState<ScreenshotDto[]>([]);
|
||||||
|
|
||||||
const { loading: pendingGetLedColorsByConfig, execute: onPickerChange } =
|
const { loading: pendingGetLedColorsByConfig, execute: onDisplayConfigChange } =
|
||||||
useAsyncCallback(async (value: DisplayConfig) => {
|
useAsyncCallback(async (value: DisplayConfig) => {
|
||||||
console.log(value);
|
console.log('onDisplayConfigChange', value);
|
||||||
const screenshot = await getScreenshotByConfig(value);
|
const screenshot = await getScreenshotByConfig(value);
|
||||||
setScreenshotOfDisplays((old) => {
|
setScreenshotOfDisplays((old) => {
|
||||||
const index = old.findIndex((it) => it.config.id === screenshot.config.id);
|
const index = old.findIndex((it) => it.config.id === screenshot.config.id);
|
||||||
console.log({ old, n: update(index, screenshot, old) });
|
const newValue = update(index, screenshot, old);
|
||||||
return update(index, screenshot, old);
|
console.log({ old, n: newValue });
|
||||||
|
savedPickerConfig &&
|
||||||
|
writePickerConfig({
|
||||||
|
...savedPickerConfig,
|
||||||
|
display_configs: newValue.map((it) => it.config),
|
||||||
|
}).then(() => {
|
||||||
|
console.log('writing config is successful.', {
|
||||||
|
...savedPickerConfig,
|
||||||
|
display_configs: newValue.map((it) => it.config),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return newValue;
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('screenshot', screenshot);
|
console.log('screenshot', screenshot);
|
||||||
@ -51,15 +67,18 @@ export const Configurator: FC = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const displayConfigs = savedPickerConfig?.display_configs;
|
const displayConfigs = savedPickerConfig?.display_configs;
|
||||||
if (displayConfigs) {
|
console.log('displayConfigs change', displayConfigs);
|
||||||
|
if (displayConfigs && defaultScreenshotOfDisplays) {
|
||||||
setDisplayConfigs(displayConfigs);
|
setDisplayConfigs(displayConfigs);
|
||||||
}
|
|
||||||
}, [savedPickerConfig]);
|
|
||||||
useEffect(() => {
|
|
||||||
if (defaultScreenshotOfDisplays) {
|
|
||||||
setScreenshotOfDisplays(defaultScreenshotOfDisplays);
|
setScreenshotOfDisplays(defaultScreenshotOfDisplays);
|
||||||
|
(async () => {
|
||||||
|
for (const config of displayConfigs) {
|
||||||
|
await onDisplayConfigChange(config);
|
||||||
|
}
|
||||||
|
})().then();
|
||||||
}
|
}
|
||||||
}, [defaultScreenshotOfDisplays]);
|
}, [savedPickerConfig, onDisplayConfigChange, defaultScreenshotOfDisplays]);
|
||||||
|
useEffect(() => {}, [defaultScreenshotOfDisplays]);
|
||||||
|
|
||||||
const displays = useMemo(() => {
|
const displays = useMemo(() => {
|
||||||
if (screenshotOfDisplays) {
|
if (screenshotOfDisplays) {
|
||||||
@ -69,7 +88,7 @@ export const Configurator: FC = () => {
|
|||||||
key={index}
|
key={index}
|
||||||
config={screenshot.config}
|
config={screenshot.config}
|
||||||
screenshot={screenshot}
|
screenshot={screenshot}
|
||||||
onChange={(value) => onPickerChange(value)}
|
onChange={(value) => onDisplayConfigChange(value)}
|
||||||
/>
|
/>
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user