Skip to content

Commit

Permalink
Merge pull request project-robius#421 from kevinaboos/redesign_typing…
Browse files Browse the repository at this point in the history
…_animation

Properly implement the TypingAnimation using shader timing
  • Loading branch information
kevinaboos authored Mar 4, 2025
2 parents 8e8c20c + 9b5f1ad commit 40a9212
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 29 deletions.
6 changes: 2 additions & 4 deletions src/home/room_screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1722,13 +1722,11 @@ impl RoomScreen {
// Animate in the typing notice view (sliding it up from the bottom).
self.animator_play(cx, id!(typing_notice_animator.show));
// Start the typing notice text animation of bouncing dots.
let typing_animation = self.view.typing_animation(id!(typing_animation));
typing_animation.animate(cx);
self.view.typing_animation(id!(typing_animation)).start_animation(cx);
} else {
// Animate out the typing notice view (sliding it out towards the bottom).
self.animator_play(cx, id!(typing_notice_animator.hide));
let typing_animation = self.view.typing_animation(id!(typing_animation));
typing_animation.stop_animation();
self.view.typing_animation(id!(typing_animation)).stop_animation(cx);
}

if num_updates > 0 {
Expand Down
59 changes: 34 additions & 25 deletions src/shared/typing_animation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,60 +9,70 @@ live_design! {
width: 24,
height: 12,
flow: Down,

show_bg: true,
draw_bg: {
color: #x000
uniform freq: 5.0, // Animation frequency
uniform phase_offset: 102.0, // Phase difference
color: #x000,
uniform anim_time: 0.0,
uniform freq: 0.9, // Animation frequency
uniform phase_offset: 5.0, // Phase difference
uniform dot_radius: 1.5, // Dot radius
fn pixel(self) -> vec4 {
let sdf = Sdf2d::viewport(self.pos * self.rect_size);
let amplitude = self.rect_size.y * 0.22;
let amplitude = self.rect_size.y * 0.21;
let center_y = self.rect_size.y * 0.5;
// Create three circle SDFs
sdf.circle(
self.rect_size.x * 0.25,
amplitude * sin(self.time * self.freq) + center_y,
amplitude * sin(self.anim_time * 2.0 * PI * self.freq) + center_y,
self.dot_radius
);
sdf.fill(self.color);
sdf.circle(
self.rect_size.x * 0.5,
amplitude * sin(self.time * self.freq + self.phase_offset) + center_y,
amplitude * sin(self.anim_time * 2.0 * PI * self.freq + self.phase_offset) + center_y,
self.dot_radius
);
sdf.fill(self.color);
sdf.circle(
self.rect_size.x * 0.75,
amplitude * sin(self.time * self.freq + self.phase_offset * 2) + center_y,
amplitude * sin(self.anim_time * 2.0 * PI * self.freq + self.phase_offset * 2) + center_y,
self.dot_radius
);
sdf.fill(self.color);
return sdf.result;
}
}

animator: {
dots = {
default: off,
off = {
from: {all: Forward {duration: 0.0}}
apply: {
draw_bg: {anim_time: 0.0}
}
}
on = {
from: {all: Loop {duration: 1.0, end: 1.0}}
apply: {
draw_bg: {anim_time: [{time: 0.0, value: 0.0}, {time: 1.0, value: 1.0}]}
}
}
}
}

}
}

#[derive(Live, LiveHook, Widget)]
pub struct TypingAnimation {
#[deref] view: View,
#[live] time: f32,
#[rust] next_frame: NextFrame,
#[rust] is_play: bool,
#[animator] animator: Animator,
}
impl Widget for TypingAnimation {
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
if let Some(ne) = self.next_frame.is_event(event) {
self.time += ne.time as f32;
self.time = (self.time.round() as u32 % 360) as f32;
self.redraw(cx);
if !self.is_play {
return
}
self.next_frame = cx.new_next_frame();
}

self.animator_handle_event(cx, event);
self.view.handle_event(cx, event, scope);
}

Expand All @@ -74,16 +84,15 @@ impl Widget for TypingAnimation {

impl TypingAnimationRef {
/// Starts animation of the bouncing dots.
pub fn animate(&self, cx: &mut Cx) {
pub fn start_animation(&self, cx: &mut Cx) {
if let Some(mut inner) = self.borrow_mut() {
inner.is_play = true;
inner.next_frame = cx.new_next_frame();
inner.animator_play(cx, id!(dots.on));
}
}
/// Stops animation of the bouncing dots.
pub fn stop_animation(&self) {
pub fn stop_animation(&self, cx: &mut Cx) {
if let Some(mut inner) = self.borrow_mut() {
inner.is_play = false;
inner.animator_play(cx, id!(dots.off));
}
}
}

0 comments on commit 40a9212

Please sign in to comment.