#![allow(dead_code)]
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use std::sync::{Arc, LazyLock};
use std::time::{Duration, Instant};
use tokio::sync::broadcast;
const BLINK_INTERVAL_MS: u64 = 600;
struct BlinkClock {
start: Instant,
subscriber_count: AtomicU64,
focused: AtomicBool,
sender: broadcast::Sender<()>,
}
static BLINK_CLOCK: LazyLock<Arc<BlinkClock>> = LazyLock::new(|| {
let (tx, _) = broadcast::channel::<()>(1);
Arc::new(BlinkClock {
start: Instant::now(),
subscriber_count: AtomicU64::new(0),
focused: AtomicBool::new(true),
sender: tx,
})
});
pub struct BlinkSubscription {
enabled: bool,
interval_ms: u64,
}
impl BlinkSubscription {
pub fn is_visible(&self) -> bool {
if !self.enabled || !BLINK_CLOCK.focused.load(Ordering::Relaxed) {
return true;
}
let elapsed_ms = BLINK_CLOCK.start.elapsed().as_millis() as u64;
(elapsed_ms / self.interval_ms) % 2 == 0
}
}
impl Drop for BlinkSubscription {
fn drop(&mut self) {
BLINK_CLOCK
.subscriber_count
.fetch_sub(1, Ordering::Relaxed);
}
}
pub fn use_blink(enabled: bool, interval_ms: Option<u64>) -> BlinkSubscription {
let interval = interval_ms.unwrap_or(BLINK_INTERVAL_MS);
BLINK_CLOCK
.subscriber_count
.fetch_add(1, Ordering::Relaxed);
BlinkSubscription {
enabled,
interval_ms: interval,
}
}
pub fn set_blink_clock_focused(focused: bool) {
BLINK_CLOCK.focused.store(focused, Ordering::Relaxed);
}
pub async fn run_blink_clock(interval_ms: u64) {
let mut interval = tokio::time::interval(Duration::from_millis(interval_ms));
loop {
interval.tick().await;
if BLINK_CLOCK.focused.load(Ordering::Relaxed)
&& BLINK_CLOCK.subscriber_count.load(Ordering::Relaxed) > 0
{
let _ = BLINK_CLOCK.sender.send(());
}
}
}