feature/gui-configuration:支持从 GUI 配置程序。 #4

Merged
Ivan merged 19 commits from feature/gui-configuration into master 2023-01-26 23:44:19 +08:00
6 changed files with 145 additions and 17 deletions
Showing only changes of commit 1c38fd970e - Show all commits

10
src-tauri/Cargo.lock generated
View File

@ -584,6 +584,7 @@ dependencies = [
"serde_json", "serde_json",
"tauri", "tauri",
"tauri-build", "tauri-build",
"test_dir",
"time", "time",
"tokio", "tokio",
"tracing", "tracing",
@ -3165,6 +3166,15 @@ dependencies = [
"utf-8", "utf-8",
] ]
[[package]]
name = "test_dir"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fc19daf9fc57fadcf740c4abaaa0cd08d9ce22a2a0629aaf6cbd9ae4b80683a"
dependencies = [
"rand 0.8.5",
]
[[package]] [[package]]
name = "thin-slice" name = "thin-slice"
version = "0.1.1" version = "0.1.1"

View File

@ -41,3 +41,6 @@ default = [ "custom-protocol" ]
# this feature is used used for production builds where `devPath` points to the filesystem # this feature is used used for production builds where `devPath` points to the filesystem
# DO NOT remove this # DO NOT remove this
custom-protocol = [ "tauri/custom-protocol" ] custom-protocol = [ "tauri/custom-protocol" ]
[dev-dependencies]
test_dir = "0.2.0"

View File

@ -1,11 +1,13 @@
#[derive(Clone, Copy)] use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Serialize, Deserialize)]
pub struct LedStripConfig { pub struct LedStripConfig {
pub index: usize, pub index: usize,
pub global_start_position: usize, pub global_start_position: usize,
pub global_end_position: usize, pub global_end_position: usize,
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy, Serialize, Deserialize)]
pub struct DisplayConfig { pub struct DisplayConfig {
pub index_of_display: usize, pub index_of_display: usize,
pub display_width: usize, pub display_width: usize,
@ -16,17 +18,6 @@ pub struct DisplayConfig {
pub right_led_strip: LedStripConfig, pub right_led_strip: LedStripConfig,
} }
#[derive(Clone, Copy)]
pub enum LedFlowX {
LR, // from left to right
RL, // from right to left
}
#[derive(Clone, Copy)]
pub enum LedFlowY {
TB, // from top to bottom
BT, // from bottom to top
}
impl DisplayConfig { impl DisplayConfig {
pub fn default(index_of_display: usize, display_width: usize, display_height: usize) -> Self { pub fn default(index_of_display: usize, display_width: usize, display_height: usize) -> Self {
Self { Self {

View File

@ -0,0 +1,122 @@
use std::{
env::current_dir,
fs::{self, File},
io::Read,
path::PathBuf,
};
use once_cell::sync::OnceCell;
use serde::{Deserialize, Serialize};
use tauri::api::path::config_dir;
use super::DisplayConfig;
#[derive(Serialize, Deserialize, Clone)]
pub struct Configuration {
config_version: u8,
display_configs: Vec<DisplayConfig>,
}
impl Configuration {
pub fn default() -> Self {
Self {
config_version: 1,
display_configs: vec![],
}
}
}
#[derive(Serialize, Deserialize)]
pub struct Manager {
config: Configuration,
}
impl Manager {
pub fn global() -> &'static Manager {
static DISPLAY_CONFIG_MANAGE: OnceCell<Manager> = OnceCell::new();
DISPLAY_CONFIG_MANAGE.get_or_init(|| Self::init_from_disk())
}
pub fn default() -> Self {
Self::new(Configuration::default())
}
pub fn new(config: Configuration) -> Self {
Self { config }
}
pub fn get_config_file_path() -> PathBuf {
config_dir()
.unwrap_or(current_dir().unwrap())
.join("display_config.json")
}
pub fn init_from_disk() -> Self {
let config_file_path = Self::get_config_file_path();
match Self::read_config_from_disk(config_file_path) {
Ok(config) => Self::new(config),
Err(_) => Self::default(),
}
}
pub fn read_config_from_disk(config_file_path: PathBuf) -> anyhow::Result<Configuration> {
let mut file = File::open(config_file_path)
.map_err(|error| anyhow::anyhow!("config file is not existed. {}", error))?;
let mut contents = String::new();
file.read_to_string(&mut contents)
.map_err(|error| anyhow::anyhow!("can not read config file. {}", error))?;
serde_json::from_str(&contents)
.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<()> {
let contents = serde_json::to_string(&self.config)
.map_err(|error| anyhow::anyhow!("can not serialize config. {}", error))?;
fs::write(config_file_path, contents.as_bytes())
.map_err(|error| anyhow::anyhow!("can not write config file. {}", error))?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use std::fs;
use serde_json::json;
use test_dir::{DirBuilder, TestDir};
use crate::picker::config::Configuration;
#[test]
fn write_config_to_disk_should_be_successful() {
let temp = TestDir::temp().create("config_dir", test_dir::FileType::Dir);
let config_file_path = temp.path("config_dir").join("picker.config.json");
let manager = crate::picker::config::manger::Manager::default();
manager
.write_config_to_disk(config_file_path.clone())
.unwrap();
let contents = fs::read_to_string(config_file_path.clone()).unwrap();
let _config: Configuration = serde_json::from_str(contents.as_str()).unwrap();
}
#[test]
fn read_config_to_disk_should_be_successful() {
let temp = TestDir::temp().create("config_dir", test_dir::FileType::Dir);
let config_file_path = temp.path("config_dir").join("picker.config.json");
fs::write(
config_file_path.clone(),
json!({
"config_version": 1,
"display_configs": []
})
.to_string()
.as_bytes(),
).unwrap();
let _manager =
crate::picker::config::manger::Manager::read_config_from_disk(config_file_path.clone())
.unwrap();
}
}

View File

@ -0,0 +1,5 @@
mod display_config;
mod manger;
pub use display_config::*;
pub use manger::*;

View File

@ -5,10 +5,7 @@ use scrap::Display;
use std::sync::Arc; use std::sync::Arc;
use tokio::{sync::Mutex, task}; use tokio::{sync::Mutex, task};
use crate::picker::{ use crate::picker::{config::LedStripConfig, screen::Screen};
config::{LedFlowX, LedFlowY, LedStripConfig},
screen::Screen,
};
use super::{ use super::{
config::DisplayConfig, display_picker::DisplayPicker, led_color::LedColor, config::DisplayConfig, display_picker::DisplayPicker, led_color::LedColor,