feat(ui-gpui): Zed-style BlinkManager pattern for pulsing dot (epoch guard, 500ms timer)

This commit is contained in:
Hibryda 2026-03-19 09:20:04 +01:00
parent 84324f9ae3
commit ba74e19ff2
2 changed files with 77 additions and 109 deletions

View file

@ -10,7 +10,7 @@ use gpui::*;
use crate::state::{AgentStatus, Project, ProjectTab};
use crate::theme;
use crate::components::pulsing_dot::{PulsingDotElement, DotStatus};
use crate::components::pulsing_dot::{PulsingDot, DotStatus};
// ── Accent Colors by Index ──────────────────────────────────────────
@ -72,7 +72,7 @@ pub struct ProjectBox {
pub agent_pane: Option<Entity<crate::components::agent_pane::AgentPane>>,
/// Entity handle for the embedded terminal (Model tab)
pub terminal_view: Option<Entity<crate::terminal::renderer::TerminalView>>,
_status_dot_placeholder: (), // PulsingDotElement is created inline during render
pub status_dot: Option<Entity<PulsingDot>>,
}
impl ProjectBox {
@ -81,13 +81,25 @@ impl ProjectBox {
project,
agent_pane: None,
terminal_view: None,
_status_dot_placeholder: (),
status_dot: None,
}
}
/// Initialize sub-views. Must be called after the ProjectBox entity is created.
pub fn init_subviews(&mut self, cx: &mut Context<Self>) {
eprintln!("[ProjectBox] init_subviews for {}", self.project.name);
// Create pulsing status dot
let dot_status = match self.project.agent.status {
AgentStatus::Running => DotStatus::Running,
AgentStatus::Idle => DotStatus::Idle,
AgentStatus::Done => DotStatus::Done,
AgentStatus::Error => DotStatus::Error,
};
let dot = cx.new(|_cx| PulsingDot::new(dot_status, 8.0));
self.status_dot = Some(dot);
// NOTE: start_blinking NOT called yet — testing if app stays alive without it
// Create agent pane with demo messages
let agent_pane = cx.new(|_cx| {
crate::components::agent_pane::AgentPane::with_demo_messages()
@ -238,16 +250,8 @@ impl Render for ProjectBox {
.rounded(px(2.0))
.bg(accent),
)
// Animated status dot — custom Element, paints directly to GPU
.child({
let dot_status = match status {
AgentStatus::Running => DotStatus::Running,
AgentStatus::Idle => DotStatus::Idle,
AgentStatus::Done => DotStatus::Done,
AgentStatus::Error => DotStatus::Error,
};
PulsingDotElement::new(dot_status, 8.0)
})
// Animated status dot (Zed BlinkManager pattern)
.children(self.status_dot.clone())
// Project name
.child(
div()