agent: Polish Generating...
animation (#28379)
https://github.com/user-attachments/assets/9e798a50-9403-4e1c-a3df-2931e748b77d Release Notes: - N/A
This commit is contained in:
parent
79c9f2bbd9
commit
38d2487630
2 changed files with 61 additions and 20 deletions
|
@ -1222,17 +1222,30 @@ impl ActiveThread {
|
||||||
Label::new("Generating")
|
Label::new("Generating")
|
||||||
.color(Color::Muted)
|
.color(Color::Muted)
|
||||||
.size(LabelSize::Small)
|
.size(LabelSize::Small)
|
||||||
.with_animation(
|
.with_animations(
|
||||||
"generating-label",
|
"generating-label",
|
||||||
Animation::new(Duration::from_secs(1)).repeat(),
|
vec![
|
||||||
|mut label, delta| {
|
Animation::new(Duration::from_secs(1)),
|
||||||
let text = match delta {
|
Animation::new(Duration::from_secs(1)).repeat(),
|
||||||
d if d < 0.25 => "Generating",
|
],
|
||||||
d if d < 0.5 => "Generating.",
|
|mut label, animation_ix, delta| {
|
||||||
d if d < 0.75 => "Generating..",
|
match animation_ix {
|
||||||
_ => "Generating...",
|
0 => {
|
||||||
};
|
let chars_to_show = (delta * 10.).ceil() as usize;
|
||||||
label.set_text(text);
|
let text = &"Generating"[0..chars_to_show];
|
||||||
|
label.set_text(text);
|
||||||
|
}
|
||||||
|
1 => {
|
||||||
|
let text = match delta {
|
||||||
|
d if d < 0.25 => "Generating",
|
||||||
|
d if d < 0.5 => "Generating.",
|
||||||
|
d if d < 0.75 => "Generating..",
|
||||||
|
_ => "Generating...",
|
||||||
|
};
|
||||||
|
label.set_text(text);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
label
|
label
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
@ -3,6 +3,7 @@ use std::time::{Duration, Instant};
|
||||||
use crate::{AnyElement, App, Element, ElementId, GlobalElementId, IntoElement, Window};
|
use crate::{AnyElement, App, Element, ElementId, GlobalElementId, IntoElement, Window};
|
||||||
|
|
||||||
pub use easing::*;
|
pub use easing::*;
|
||||||
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
/// An animation that can be applied to an element.
|
/// An animation that can be applied to an element.
|
||||||
pub struct Animation {
|
pub struct Animation {
|
||||||
|
@ -50,6 +51,24 @@ pub trait AnimationExt {
|
||||||
animation: Animation,
|
animation: Animation,
|
||||||
animator: impl Fn(Self, f32) -> Self + 'static,
|
animator: impl Fn(Self, f32) -> Self + 'static,
|
||||||
) -> AnimationElement<Self>
|
) -> AnimationElement<Self>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
AnimationElement {
|
||||||
|
id: id.into(),
|
||||||
|
element: Some(self),
|
||||||
|
animator: Box::new(move |this, _, value| animator(this, value)),
|
||||||
|
animations: smallvec::smallvec![animation],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Render this component or element with a chain of animations
|
||||||
|
fn with_animations(
|
||||||
|
self,
|
||||||
|
id: impl Into<ElementId>,
|
||||||
|
animations: Vec<Animation>,
|
||||||
|
animator: impl Fn(Self, usize, f32) -> Self + 'static,
|
||||||
|
) -> AnimationElement<Self>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
|
@ -57,7 +76,7 @@ pub trait AnimationExt {
|
||||||
id: id.into(),
|
id: id.into(),
|
||||||
element: Some(self),
|
element: Some(self),
|
||||||
animator: Box::new(animator),
|
animator: Box::new(animator),
|
||||||
animation,
|
animations: animations.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,8 +87,8 @@ impl<E> AnimationExt for E {}
|
||||||
pub struct AnimationElement<E> {
|
pub struct AnimationElement<E> {
|
||||||
id: ElementId,
|
id: ElementId,
|
||||||
element: Option<E>,
|
element: Option<E>,
|
||||||
animation: Animation,
|
animations: SmallVec<[Animation; 1]>,
|
||||||
animator: Box<dyn Fn(E, f32) -> E + 'static>,
|
animator: Box<dyn Fn(E, usize, f32) -> E + 'static>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E> AnimationElement<E> {
|
impl<E> AnimationElement<E> {
|
||||||
|
@ -91,6 +110,7 @@ impl<E: IntoElement + 'static> IntoElement for AnimationElement<E> {
|
||||||
|
|
||||||
struct AnimationState {
|
struct AnimationState {
|
||||||
start: Instant,
|
start: Instant,
|
||||||
|
animation_ix: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: IntoElement + 'static> Element for AnimationElement<E> {
|
impl<E: IntoElement + 'static> Element for AnimationElement<E> {
|
||||||
|
@ -108,22 +128,30 @@ impl<E: IntoElement + 'static> Element for AnimationElement<E> {
|
||||||
cx: &mut App,
|
cx: &mut App,
|
||||||
) -> (crate::LayoutId, Self::RequestLayoutState) {
|
) -> (crate::LayoutId, Self::RequestLayoutState) {
|
||||||
window.with_element_state(global_id.unwrap(), |state, window| {
|
window.with_element_state(global_id.unwrap(), |state, window| {
|
||||||
let state = state.unwrap_or_else(|| AnimationState {
|
let mut state = state.unwrap_or_else(|| AnimationState {
|
||||||
start: Instant::now(),
|
start: Instant::now(),
|
||||||
|
animation_ix: 0,
|
||||||
});
|
});
|
||||||
let mut delta =
|
let animation_ix = state.animation_ix;
|
||||||
state.start.elapsed().as_secs_f32() / self.animation.duration.as_secs_f32();
|
|
||||||
|
let mut delta = state.start.elapsed().as_secs_f32()
|
||||||
|
/ self.animations[animation_ix].duration.as_secs_f32();
|
||||||
|
|
||||||
let mut done = false;
|
let mut done = false;
|
||||||
if delta > 1.0 {
|
if delta > 1.0 {
|
||||||
if self.animation.oneshot {
|
if self.animations[animation_ix].oneshot {
|
||||||
done = true;
|
if animation_ix >= self.animations.len() - 1 {
|
||||||
|
done = true;
|
||||||
|
} else {
|
||||||
|
state.start = Instant::now();
|
||||||
|
state.animation_ix += 1;
|
||||||
|
}
|
||||||
delta = 1.0;
|
delta = 1.0;
|
||||||
} else {
|
} else {
|
||||||
delta %= 1.0;
|
delta %= 1.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let delta = (self.animation.easing)(delta);
|
let delta = (self.animations[animation_ix].easing)(delta);
|
||||||
|
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
(0.0..=1.0).contains(&delta),
|
(0.0..=1.0).contains(&delta),
|
||||||
|
@ -131,7 +159,7 @@ impl<E: IntoElement + 'static> Element for AnimationElement<E> {
|
||||||
);
|
);
|
||||||
|
|
||||||
let element = self.element.take().expect("should only be called once");
|
let element = self.element.take().expect("should only be called once");
|
||||||
let mut element = (self.animator)(element, delta).into_any_element();
|
let mut element = (self.animator)(element, animation_ix, delta).into_any_element();
|
||||||
|
|
||||||
if !done {
|
if !done {
|
||||||
window.request_animation_frame();
|
window.request_animation_frame();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue