fix(progress_bar): sync determinate animation clock on target change

This prevents the time delta from becoming very large when the widget hasn't animated for a bit, leading to snapping instead of a smooth animation.
Also prevents animating on widget creation, since it doesn't feel good in `cosmic-osd`.
This commit is contained in:
Vukašin Vojinović 2026-04-22 12:26:29 +02:00 committed by Michael Murphy
parent 8b4c8adec8
commit dad5f1e273

View file

@ -4,29 +4,38 @@ use std::time::Duration;
const LAG: f32 = 0.1; const LAG: f32 = 0.1;
#[derive(Default)]
pub struct Progress { pub struct Progress {
pub current: f32, pub current: f32,
last: Instant, target: Option<f32>,
} last: Option<Instant>,
impl Default for Progress {
fn default() -> Self {
Self {
current: 0.0,
last: Instant::now(),
}
}
} }
impl Progress { impl Progress {
/// Smoothly chases `target` using exponential decay. /// Smoothly chases `target` using exponential decay.
/// Returns `true` if still animating and a redraw should be requested. /// Returns `true` if a redraw should be requested.
pub fn update(&mut self, target: f32, now: Instant) -> bool { pub fn update(&mut self, target: f32, now: Instant) -> bool {
let dt = (now - self.last).as_secs_f32(); // Don't animate on start
self.last = now; let Some(last) = self.last else {
let next = self.current + (target - self.current) * (1.0 - (-dt / LAG).exp()); self.current = target;
if (next - target).abs() > 0.001 { self.target = Some(target);
self.current = next; self.last = Some(now);
return false;
};
// Sync animation clock when target changes
if self.target != Some(target) {
self.target = Some(target);
self.last = Some(now);
return true;
}
let dt = (now - last).as_secs_f32();
self.last = Some(now);
let diff = target - self.current;
if diff.abs() > 0.001 {
self.current += diff * (1.0 - (-dt / LAG).exp());
true true
} else { } else {
self.current = target; self.current = target;