diff --git a/crates/notedeck/src/debouncer.rs b/crates/notedeck/src/debouncer.rs new file mode 100644 index 00000000..02121685 --- /dev/null +++ b/crates/notedeck/src/debouncer.rs @@ -0,0 +1,35 @@ +use std::time::{Duration, Instant}; + +/// A simple debouncer that tracks when an action was last performed +/// and determines if enough time has passed to perform it again. +#[derive(Debug)] +pub struct Debouncer { + delay: Duration, + last_action: Instant, +} + +impl Debouncer { + /// Creates a new Debouncer with the specified delay + pub fn new(delay: Duration) -> Self { + Self { + delay, + last_action: Instant::now() - delay, // Start ready to act + } + } + + /// Sets a new delay value and returns self for method chaining + pub fn with_delay(mut self, delay: Duration) -> Self { + self.delay = delay; + self + } + + /// Checks if enough time has passed since the last action + pub fn should_act(&self) -> bool { + self.last_action.elapsed() >= self.delay + } + + /// Marks an action as performed, updating the timestamp + pub fn bounce(&mut self) { + self.last_action = Instant::now(); + } +} diff --git a/crates/notedeck/src/lib.rs b/crates/notedeck/src/lib.rs index aa13ff86..db6cd175 100644 --- a/crates/notedeck/src/lib.rs +++ b/crates/notedeck/src/lib.rs @@ -2,6 +2,7 @@ mod accounts; mod app; mod args; mod context; +pub mod debouncer; mod error; pub mod filter; pub mod fonts; diff --git a/crates/notedeck/src/timed_serializer.rs b/crates/notedeck/src/timed_serializer.rs index a9e52717..5dda904d 100644 --- a/crates/notedeck/src/timed_serializer.rs +++ b/crates/notedeck/src/timed_serializer.rs @@ -1,14 +1,13 @@ -use std::time::{Duration, Instant}; - +use crate::debouncer::Debouncer; use crate::{storage, DataPath, DataPathType, Directory}; use serde::{Deserialize, Serialize}; -use tracing::info; +use std::time::Duration; +use tracing::info; // Adjust this import path as needed pub struct TimedSerializer Deserialize<'de>> { directory: Directory, file_name: String, - delay: Duration, - last_saved: Instant, + debouncer: Debouncer, saved_item: Option, } @@ -16,28 +15,24 @@ impl Deserialize<'de>> TimedSerialize pub fn new(path: &DataPath, path_type: DataPathType, file_name: String) -> Self { let directory = Directory::new(path.path(path_type)); let delay = Duration::from_millis(1000); + let debouncer = Debouncer::new(delay); Self { directory, file_name, - delay, - last_saved: Instant::now() - delay, + debouncer, saved_item: None, } } pub fn with_delay(mut self, delay: Duration) -> Self { - self.delay = delay; + self.debouncer = self.debouncer.with_delay(delay); self } - fn should_save(&self) -> bool { - self.last_saved.elapsed() >= self.delay - } - // returns whether successful pub fn try_save(&mut self, cur_item: T) -> bool { - if self.should_save() { + if self.debouncer.should_act() { if let Some(saved_item) = self.saved_item { if saved_item != cur_item { return self.save(cur_item); @@ -53,7 +48,6 @@ impl Deserialize<'de>> TimedSerialize if self.saved_item.is_some() { return self.saved_item; } - if let Ok(file_contents) = self.directory.get_file(self.file_name.clone()) { if let Ok(item) = serde_json::from_str::(&file_contents) { return Some(item); @@ -61,7 +55,6 @@ impl Deserialize<'de>> TimedSerialize } else { info!("Could not find file {}", self.file_name); } - None } @@ -75,12 +68,11 @@ impl Deserialize<'de>> TimedSerialize .is_ok() { info!("wrote item {}", serialized_item); - self.last_saved = Instant::now(); + self.debouncer.bounce(); self.saved_item = Some(cur_item); return true; } } - false } }