From 9b5f1ad5d5224dcc3ba8eeb2e18d2545cb59ea86 Mon Sep 17 00:00:00 2001 From: Kevin Boos Date: Tue, 4 Mar 2025 11:50:20 -0800 Subject: [PATCH] Properly implement the TypingAnimation using shader timing This removes unnecessary redraws of the parent view stack too. --- src/home/room_screen.rs | 6 ++-- src/shared/typing_animation.rs | 59 ++++++++++++++++++++-------------- 2 files changed, 36 insertions(+), 29 deletions(-) diff --git a/src/home/room_screen.rs b/src/home/room_screen.rs index 51ed2d4a..80345773 100644 --- a/src/home/room_screen.rs +++ b/src/home/room_screen.rs @@ -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 { diff --git a/src/shared/typing_animation.rs b/src/shared/typing_animation.rs index 92704101..a9d4c5b6 100644 --- a/src/shared/typing_animation.rs +++ b/src/shared/typing_animation.rs @@ -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); } @@ -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)); } } }