feat(window-state): add group

pull/531/head
luohy 2 years ago
parent cdb77c4b65
commit 9a32cb9ccd

@ -4,11 +4,7 @@
use bitflags::bitflags; use bitflags::bitflags;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tauri::{ use tauri::{plugin::{Builder as PluginBuilder, TauriPlugin}, LogicalSize, Manager, Monitor, PhysicalPosition, PhysicalSize, RunEvent, Runtime, Window, WindowEvent, State, AppHandle};
plugin::{Builder as PluginBuilder, TauriPlugin},
LogicalSize, Manager, Monitor, PhysicalPosition, PhysicalSize, RunEvent, Runtime, Window,
WindowEvent,
};
use std::{ use std::{
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
@ -81,6 +77,7 @@ impl Default for WindowState {
} }
struct WindowStateCache(Arc<Mutex< HashMap<String, WindowState>>>); struct WindowStateCache(Arc<Mutex< HashMap<String, WindowState>>>);
struct GroupStateCache(Arc<Mutex<Vec<Group>>>);
pub trait AppHandleExt { pub trait AppHandleExt {
/// Saves all open windows state to disk /// Saves all open windows state to disk
fn save_window_state(&self, flags: StateFlags) -> Result<()>; fn save_window_state(&self, flags: StateFlags) -> Result<()>;
@ -92,10 +89,14 @@ impl<R: Runtime> AppHandleExt for tauri::AppHandle<R> {
let state_path = app_dir.join(STATE_FILENAME); let state_path = app_dir.join(STATE_FILENAME);
let cache = self.state::<WindowStateCache>(); let cache = self.state::<WindowStateCache>();
let mut state = cache.0.lock().unwrap(); let mut state = cache.0.lock().unwrap();
for (label, s) in state.iter_mut() {
if let Some(window) = self.get_window(label) { let groups = self.state::<GroupStateCache>();
window.update_state(s, flags)?; let binding = groups.0.clone();
} let binding = binding.lock().unwrap();
let groups = binding.as_ref();
for window in self.windows().values() {
window.update_state(state.get(group_name(groups, window.label().into())), flags)?;
} }
create_dir_all(&app_dir) create_dir_all(&app_dir)
@ -111,6 +112,13 @@ impl<R: Runtime> AppHandleExt for tauri::AppHandle<R> {
} }
} }
fn group_name_by_state(groups: State<GroupStateCache>, label: String) {
let binding = groups.0.clone();
let binding = binding.lock().unwrap();
let groups = binding.as_ref();
let key = group_name(groups, label);
}
pub trait WindowExt { pub trait WindowExt {
/// Restores this window state from disk /// Restores this window state from disk
fn restore_state(&self, flags: StateFlags) -> tauri::Result<()>; fn restore_state(&self, flags: StateFlags) -> tauri::Result<()>;
@ -121,9 +129,12 @@ impl<R: Runtime> WindowExt for Window<R> {
let cache = self.state::<WindowStateCache>(); let cache = self.state::<WindowStateCache>();
let mut c = cache.0.lock().unwrap(); let mut c = cache.0.lock().unwrap();
let groups = self.state::<GroupStateCache>();
let key = group_name_by_state(groups, self.label().into());
let mut should_show = true; let mut should_show = true;
if let Some(state) = c.get(self.label()) { if let Some(state) = c.get(key) {
// avoid restoring the default zeroed state // avoid restoring the default zeroed state
if *state == WindowState::default() { if *state == WindowState::default() {
return Ok(()); return Ok(());
@ -197,7 +208,7 @@ impl<R: Runtime> WindowExt for Window<R> {
metadata.fullscreen = self.is_fullscreen()?; metadata.fullscreen = self.is_fullscreen()?;
} }
c.insert(self.label().into(), metadata); c.insert(key.into(), metadata);
} }
if flags.contains(StateFlags::VISIBLE) && should_show { if flags.contains(StateFlags::VISIBLE) && should_show {
@ -265,11 +276,36 @@ impl<R: Runtime> WindowExtInternal for Window<R> {
} }
} }
pub struct Group {
name: String,
match_rule: fn(&String) -> bool,
}
impl Group {
pub fn new(name: String, match_rule: fn(&String) -> bool) -> Group {
Group { name, match_rule }
}
pub fn filter(&self, label: &String) -> bool {
(self.match_rule)(label)
}
}
/// get group name which match first rule
pub fn group_name(groups: &Vec<Group>, label: String) -> String {
groups
.iter()
.filter(|g| g.filter(&label))
.nth(0)
.map_or(label, |g| g.name.clone())
}
#[derive(Default)] #[derive(Default)]
pub struct Builder { pub struct Builder {
denylist: HashSet<String>, denylist: HashSet<String>,
skip_initial_state: HashSet<String>, skip_initial_state: HashSet<String>,
state_flags: StateFlags, state_flags: StateFlags,
groups: Vec<Group>,
} }
impl Builder { impl Builder {
@ -292,6 +328,12 @@ impl Builder {
self self
} }
/// add group
pub fn add_group(mut self, group: Group) -> Self {
self.groups.push(group);
self
}
pub fn build<R: Runtime>(self) -> TauriPlugin<R> { pub fn build<R: Runtime>(self) -> TauriPlugin<R> {
let flags = self.state_flags; let flags = self.state_flags;
PluginBuilder::new("window-state") PluginBuilder::new("window-state")
@ -318,6 +360,7 @@ impl Builder {
Default::default() Default::default()
}; };
app.manage(WindowStateCache(cache)); app.manage(WindowStateCache(cache));
app.manage(GroupStateCache(Arc::new(Mutex::new(self.groups))));
Ok(()) Ok(())
}) })
.on_webview_ready(move |window| { .on_webview_ready(move |window| {
@ -335,20 +378,23 @@ impl Builder {
let window_clone = window.clone(); let window_clone = window.clone();
let flags = self.state_flags; let flags = self.state_flags;
let groups = window.state::<GroupStateCache>();
let key = group_name_by_state(groups, label);
// insert a default state if this window should be tracked and // insert a default state if this window should be tracked and
// the disk cache doesn't have a state for it // the disk cache doesn't have a state for it
{ {
cache cache
.lock() .lock()
.unwrap() .unwrap()
.entry(label.clone()) .entry(key)
.or_insert_with(WindowState::default); .or_insert_with(WindowState::default);
} }
window.on_window_event(move |e| { window.on_window_event(move |e| {
if let WindowEvent::CloseRequested { .. } = e { if let WindowEvent::CloseRequested { .. } = e {
let mut c = cache.lock().unwrap(); let mut c = cache.lock().unwrap();
if let Some(state) = c.get_mut(&label) { if let Some(state) = c.get_mut(&key) {
let _ = window_clone.update_state(state, flags); let _ = window_clone.update_state(state, flags);
} }
} }

Loading…
Cancel
Save