feat: 支持记住显示器配置。

This commit is contained in:
Ivan Li 2023-05-11 14:13:14 +08:00
parent 8b124f8182
commit 3a23e1760b
3 changed files with 139 additions and 4 deletions

View File

@ -14,7 +14,7 @@ impl DisplayHandler {
pub async fn fetch_state(&self) { pub async fn fetch_state(&self) {
let mut controller = self.controller.write().await; let mut controller = self.controller.write().await;
let mut temp_state = DisplayState::default(); let mut temp_state = self.state.read().await.clone();
match controller.handle.get_vcp_feature(0x10) { match controller.handle.get_vcp_feature(0x10) {
Ok(value) => { Ok(value) => {

View File

@ -34,3 +34,15 @@ impl DisplayState {
} }
} }
} }
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct DisplayStateWrapper {
pub version: u8,
pub states: Vec<DisplayState>,
}
impl DisplayStateWrapper {
pub fn new(states: Vec<DisplayState>) -> Self {
Self { version: 1, states }
}
}

View File

@ -1,23 +1,31 @@
use std::{ use std::{
env::current_dir,
sync::Arc, sync::Arc,
time::{Duration, SystemTime}, time::{Duration, SystemTime},
}; };
use ddc_hi::Display; use ddc_hi::Display;
use paris::{error, info, warn}; use paris::{error, info, warn};
use tauri::api::path::config_dir;
use tokio::{ use tokio::{
sync::{broadcast, watch, OnceCell, RwLock}, sync::{broadcast, watch, OnceCell, RwLock},
task::yield_now, task::yield_now,
}; };
use crate::rpc::{BoardMessageChannels, DisplaySetting}; use crate::{
display::DisplayStateWrapper,
rpc::{BoardMessageChannels, DisplaySetting},
};
use super::{display_handler::DisplayHandler, display_state::DisplayState}; use super::{display_handler::DisplayHandler, display_state::DisplayState};
const CONFIG_FILE_NAME: &str = "cc.ivanli.ambient_light/displays.toml";
pub struct DisplayManager { pub struct DisplayManager {
displays: Arc<RwLock<Vec<Arc<RwLock<DisplayHandler>>>>>, displays: Arc<RwLock<Vec<Arc<RwLock<DisplayHandler>>>>>,
setting_request_handler: Option<tokio::task::JoinHandle<()>>, setting_request_handler: Option<tokio::task::JoinHandle<()>>,
displays_changed_sender: Arc<watch::Sender<Vec<DisplayState>>>, displays_changed_sender: Arc<watch::Sender<Vec<DisplayState>>>,
auto_save_state_handler: Option<tokio::task::JoinHandle<()>>,
} }
impl DisplayManager { impl DisplayManager {
@ -35,12 +43,29 @@ impl DisplayManager {
displays: Arc::new(RwLock::new(Vec::new())), displays: Arc::new(RwLock::new(Vec::new())),
setting_request_handler: None, setting_request_handler: None,
displays_changed_sender, displays_changed_sender,
auto_save_state_handler: None,
}; };
instance.fetch_displays().await; instance.fetch_displays().await;
instance.restore_states().await;
instance.fetch_state_of_displays().await;
instance.subscribe_setting_request(); instance.subscribe_setting_request();
instance.auto_save_state_of_displays();
instance instance
} }
fn auto_save_state_of_displays(&mut self) {
let displays = self.displays.clone();
let handler = tokio::spawn(async move {
loop {
tokio::time::sleep(Duration::from_secs(10)).await;
Self::save_states(displays.clone()).await;
}
});
self.auto_save_state_handler = Some(handler);
}
async fn fetch_displays(&self) { async fn fetch_displays(&self) {
let mut displays = self.displays.write().await; let mut displays = self.displays.write().await;
displays.clear(); displays.clear();
@ -55,12 +80,19 @@ impl DisplayManager {
controller: controller.clone(), controller: controller.clone(),
}; };
handler.fetch_state().await;
displays.push(Arc::new(RwLock::new(handler))); displays.push(Arc::new(RwLock::new(handler)));
} }
} }
async fn fetch_state_of_displays(&self) {
let displays = self.displays.read().await;
for display in displays.iter() {
let display = display.read().await;
display.fetch_state().await;
}
}
pub async fn get_displays(&self) -> Vec<DisplayState> { pub async fn get_displays(&self) -> Vec<DisplayState> {
let displays = self.displays.read().await; let displays = self.displays.read().await;
let mut states = Vec::new(); let mut states = Vec::new();
@ -132,6 +164,93 @@ impl DisplayManager {
self.setting_request_handler = Some(handler); self.setting_request_handler = Some(handler);
} }
async fn restore_states(&self) {
let path = config_dir()
.unwrap_or(current_dir().unwrap())
.join(CONFIG_FILE_NAME);
if !path.exists() {
log::info!("config file not found: {}. skip read.", path.display());
return;
}
let text = std::fs::read_to_string(path);
if let Err(err) = text {
log::error!("failed to read config file: {}", err);
return;
}
let text = text.unwrap();
let wrapper = toml::from_str::<DisplayStateWrapper>(&text);
if let Err(err) = wrapper {
log::error!("failed to parse display states file: {}", err);
return;
}
let states = wrapper.unwrap().states;
let displays = self.displays.read().await;
for (index, display) in displays.iter().enumerate() {
let display = display.read().await;
let mut state = display.state.write().await;
let saved = states.get(index);
if let Some(saved) = saved {
state.brightness = saved.brightness;
state.contrast = saved.contrast;
state.mode = saved.mode;
log::info!("restore display config. display#{}: {:?}", index, state);
}
}
log::info!(
"restore display config. store displays: {}, online displays: {}",
states.len(),
displays.len()
);
}
async fn save_states(displays: Arc<RwLock<Vec<Arc<RwLock<DisplayHandler>>>>>) {
let path = config_dir()
.unwrap_or(current_dir().unwrap())
.join(CONFIG_FILE_NAME);
let displays = displays.read().await;
let mut states = Vec::new();
for display in displays.iter() {
let state = display.read().await.state.read().await.clone();
states.push(state);
}
let wrapper = DisplayStateWrapper::new(states);
let text = toml::to_string(&wrapper);
if let Err(err) = text {
log::error!("failed to serialize display states: {}", err);
log::error!("display states: {:?}", &wrapper);
return;
}
let text = text.unwrap();
if path.exists() {
if let Err(err) = std::fs::remove_file(&path) {
log::error!("failed to remove old config file: {}", err);
return;
}
}
if let Err(err) = std::fs::write(&path, text) {
log::error!("failed to write config file: {}", err);
return;
}
log::info!(
"save display config. store displays: {}, online displays: {}",
wrapper.states.len(),
displays.len()
);
}
pub fn subscribe_displays_changed(&self) -> watch::Receiver<Vec<DisplayState>> { pub fn subscribe_displays_changed(&self) -> watch::Receiver<Vec<DisplayState>> {
self.displays_changed_sender.subscribe() self.displays_changed_sender.subscribe()
} }
@ -143,5 +262,9 @@ impl Drop for DisplayManager {
if let Some(handler) = self.setting_request_handler.take() { if let Some(handler) = self.setting_request_handler.take() {
handler.abort(); handler.abort();
} }
if let Some(handler) = self.auto_save_state_handler.take() {
handler.abort();
}
} }
} }