notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

commit 5fde3277a1a795adf3fd5e91b212b33eb7886244
parent d19e4b1d2bb8300b22f0c6c032c6aeb6cd7f9156
Author: William Casarin <jb55@jb55.com>
Date:   Thu,  6 Mar 2025 15:10:47 -0800

notedeck: add debouncer util

I wanted this separate from the timed serializer so I could use it for
other things

Signed-off-by: William Casarin <jb55@jb55.com>

Diffstat:
Acrates/notedeck/src/debouncer.rs | 35+++++++++++++++++++++++++++++++++++
Mcrates/notedeck/src/lib.rs | 1+
Mcrates/notedeck/src/timed_serializer.rs | 26+++++++++-----------------
3 files changed, 45 insertions(+), 17 deletions(-)

diff --git a/crates/notedeck/src/debouncer.rs 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 @@ -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 @@ -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<T: PartialEq + Copy + Serialize + for<'de> Deserialize<'de>> { directory: Directory, file_name: String, - delay: Duration, - last_saved: Instant, + debouncer: Debouncer, saved_item: Option<T>, } @@ -16,28 +15,24 @@ impl<T: PartialEq + Copy + Serialize + for<'de> 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<T: PartialEq + Copy + Serialize + for<'de> 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::<T>(&file_contents) { return Some(item); @@ -61,7 +55,6 @@ impl<T: PartialEq + Copy + Serialize + for<'de> Deserialize<'de>> TimedSerialize } else { info!("Could not find file {}", self.file_name); } - None } @@ -75,12 +68,11 @@ impl<T: PartialEq + Copy + Serialize + for<'de> 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 } }