From 651d96d89794a7b45b02175a7948673404bf7b20 Mon Sep 17 00:00:00 2001 From: Alex Zhang Date: Tue, 10 Jun 2025 00:24:12 -0400 Subject: [PATCH] Add colors and animation update --- src/cmd/submit.rs | 16 ++++-- src/utils/mod.rs | 107 +++++++++++++++++++++++++++----------- src/views/loading_page.rs | 14 ++++- src/views/result_page.rs | 27 ++++++---- 4 files changed, 119 insertions(+), 45 deletions(-) diff --git a/src/cmd/submit.rs b/src/cmd/submit.rs index 6745ea2..938ff81 100644 --- a/src/cmd/submit.rs +++ b/src/cmd/submit.rs @@ -665,12 +665,18 @@ pub async fn run_submit_tui( let state = &mut app.result_page_state; let mut result_page = ResultPage::new(result_text.clone(), state); + let mut last_draw = std::time::Instant::now(); while !state.ack { - terminal - .draw(|frame: &mut Frame| { - frame.render_stateful_widget(&result_page, frame.size(), state); - }) - .unwrap(); + // Force redraw every 100ms for smooth animation + let now = std::time::Instant::now(); + if now.duration_since(last_draw) >= std::time::Duration::from_millis(100) { + terminal + .draw(|frame: &mut Frame| { + frame.render_stateful_widget(&result_page, frame.size(), state); + }) + .unwrap(); + last_draw = now; + } result_page.handle_key_event(state); } diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 4e940ad..d44304a 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -48,38 +48,87 @@ pub fn get_popcorn_directives>(filepath: P) -> Result<(PopcornDir )) } -pub fn get_ascii_art() -> String { - let art = r#" - _ __ _ ______ _ - | | / / | | | ___ \ | | - | |/ / ___ _ __ _ __ ___ | | | |_/ / ___ _| |_ - | \ / _ \ '__| '_ \ / _ \| | | ___ \ / _ \| | __| - | |\ \ __/ | | | | | __/| | | |_/ /| (_) | | |_ - \_| \_/\___|_| |_| |_|\___|_/ \____/ \___/|_|\__| - - POPCORN CLI - GPU MODE - - ┌───────────────────────────────────────┐ - │ ┌─────┐ ┌─────┐ ┌─────┐ │ - │ │ooOoo│ │ooOoo│ │ooOoo│ │▒ - │ │oOOOo│ │oOOOo│ │oOOOo│ │▒ - │ │ooOoo│ │ooOoo│ │ooOoo│ ┌────────┐ │▒ - │ └─────┘ └─────┘ └─────┘ │████████│ │▒ - │ │████████│ │▒ - │ ┌────────────────────────┐ │████████│ │▒ - │ │ │ │████████│ │▒ - │ │ POPCORN GPU COMPUTE │ └────────┘ │▒ - │ │ │ │▒ - │ └────────────────────────┘ │▒ - │ │▒ - └───────────────────────────────────────┘▒ - ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ - ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ - "#; +pub fn get_ascii_art_frame(frame: u16) -> String { + let frame = frame % 3; + match frame { + 0 => r#" + ▗▖ ▗▖▗▄▄▄▖▗▄▄▖ ▗▖ ▗▖▗▄▄▄▖▗▖ ▗▄▄▖ ▗▄▖ ▗▄▄▄▖ + ▐▌▗▞▘▐▌ ▐▌ ▐▌▐▛▚▖▐▌▐▌ ▐▌ ▐▌ ▐▌▐▌ ▐▌ █ + ▐▛▚▖ ▐▛▀▀▘▐▛▀▚▖▐▌ ▝▜▌▐▛▀▀▘▐▌ ▐▛▀▚▖▐▌ ▐▌ █ + ▐▌ ▐▌▐▙▄▄▖▐▌ ▐▌▐▌ ▐▌▐▙▄▄▖▐▙▄▄▖▐▙▄▞▘▝▚▄▞▘ █ + + POPCORN CLI - GPU MODE + + ┌────────────────────────────────────────────┐ + │ ╔══════════════════════════════════╗ ϟ │ + │ ║ ▄▄ Graphics Processing Unit ▄▄║ ║ │▒ + │ ║ ██████ 80GB HBM3 MEMORY █║ ║ │▒ + │ ║ ▀▀▀▀▀▀ 700W TDP █║ ║ │▒ + │ ╚══════════════════════════════════╝ │▒ + │ ┌─────┐┌─────┐┌─────┐┌─────┐┌─────┐ │▒ + │ │:::::││:::::││:::::││:::::││:::::│ │▒ + │ └─────┘└─────┘└─────┘└─────┘└─────┘ │▒ + │ ┌──────────────────────────────────┐ │▒ + │ │ discord.com/invite/gpumode │ │▒ + │ │ ═══╧═══╧═══╧═══╧═══╧═══╧═══ │ │▒ + │ └──────────────────────────────────┘ │▒ + └────────────────────────────────────────────┘▒ + ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ + ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀"#.to_string(), + 1 => r#" + ▗▖ ▗▖▗▄▄▄▖▗▄▄▖ ▗▖ ▗▖▗▄▄▄▖▗▖ ▗▄▄▖ ▗▄▖ ▗▄▄▄▖ + ▐▌▗▞▘▐▌ ▐▌ ▐▌▐▛▚▖▐▌▐▌ ▐▌ ▐▌ ▐▌▐▌ ▐▌ █ + ▐▛▚▖ ▐▛▀▀▘▐▛▀▚▖▐▌ ▝▜▌▐▛▀▀▘▐▌ ▐▛▀▚▖▐▌ ▐▌ █ + ▐▌ ▐▌▐▙▄▄▖▐▌ ▐▌▐▌ ▐▌▐▙▄▄▖▐▙▄▄▖▐▙▄▞▘▝▚▄▞▘ █ + + POPCORN CLI - GPU MODE + + ┌────────────────────────────────────────────┐ + │ ╔══════════════════════════════════╗ ϟϟ │ + │ ║ ▄▄ Graphics Processing Unit ▄▄║ ║ │▒ + │ ║ ██████ 80GB HBM3 MEMORY ███║ ║ │▒ + │ ║ ▀▀▀▀▀▀ 700W TDP ███║ ║ │▒ + │ ╚══════════════════════════════════╝ │▒ + │ ┌─────┐┌─────┐┌─────┐┌─────┐┌─────┐ │▒ + │ │:::::││:::::││:::::││:::::││:::::│ │▒ + │ └─────┘└─────┘└─────┘└─────┘└─────┘ │▒ + │ ┌──────────────────────────────────┐ │▒ + │ │ discord.com/invite/gpumode │ │▒ + │ │ ═══╧═══╧═══╧═══╧═══╧═══╧═══ │ │▒ + │ └──────────────────────────────────┘ │▒ + └────────────────────────────────────────────┘▒ + ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ + ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀"#.to_string(), + _ => r#" + ▗▖ ▗▖▗▄▄▄▖▗▄▄▖ ▗▖ ▗▖▗▄▄▄▖▗▖ ▗▄▄▖ ▗▄▖ ▗▄▄▄▖ + ▐▌▗▞▘▐▌ ▐▌ ▐▌▐▛▚▖▐▌▐▌ ▐▌ ▐▌ ▐▌▐▌ ▐▌ █ + ▐▛▚▖ ▐▛▀▀▘▐▛▀▚▖▐▌ ▝▜▌▐▛▀▀▘▐▌ ▐▛▀▚▖▐▌ ▐▌ █ + ▐▌ ▐▌▐▙▄▄▖▐▌ ▐▌▐▌ ▐▌▐▙▄▄▖▐▙▄▄▖▐▙▄▞▘▝▚▄▞▘ █ - art.to_string() + POPCORN CLI - GPU MODE + + ┌────────────────────────────────────────────┐ + │ ╔══════════════════════════════════╗ ϟϟϟ │ + │ ║ ▄▄ Graphics Processing Unit ▄▄║ ║ │▒ + │ ║ ██████ 80GB HBM3 MEMORY █████║ ║ │▒ + │ ║ ▀▀▀▀▀▀ 700W TDP █████║ ║ │▒ + │ ╚══════════════════════════════════╝ │▒ + │ ┌─────┐┌─────┐┌─────┐┌─────┐┌─────┐ │▒ + │ │:::::││:::::││:::::││:::::││:::::│ │▒ + │ └─────┘└─────┘└─────┘└─────┘└─────┘ │▒ + │ ┌──────────────────────────────────┐ │▒ + │ │ discord.com/invite/gpumode │ │▒ + │ │ ═══╧═══╧═══╧═══╧═══╧═══╧═══ │ │▒ + │ └──────────────────────────────────┘ │▒ + └────────────────────────────────────────────┘▒ + ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ + ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀"#.to_string() + } } +pub fn get_ascii_art() -> String { + get_ascii_art_frame(0) +} pub fn display_ascii_art() { let art = get_ascii_art(); diff --git a/src/views/loading_page.rs b/src/views/loading_page.rs index a01512f..9bf0d9d 100644 --- a/src/views/loading_page.rs +++ b/src/views/loading_page.rs @@ -19,7 +19,17 @@ pub struct LoadingPage { footer_area: Rect, } -const GAUGE_COLOR: Color = ratatui::style::palette::tailwind::RED.c800; +fn get_gradient_color(progress: f64) -> Color { + // Convert progress from 0-100 to 0-1 + let t = progress / 100.0; + + // Start with red (255, 0, 0) and end with green (0, 255, 0) + let r = ((1.0 - t) * 255.0) as u8; + let g = (t * 255.0) as u8; + let b = 0; + + Color::Rgb(r, g, b) +} impl StatefulWidget for &LoadingPage { type State = LoadingPageState; @@ -40,7 +50,7 @@ fn render_gauge(area: Rect, buf: &mut Buffer, state: &mut LoadingPageState) { let blk = Block::default().padding(Padding::horizontal(20)); Gauge::default() .block(blk) - .gauge_style(GAUGE_COLOR) + .gauge_style(get_gradient_color(state.progress_bar)) .ratio(state.progress_bar / 100.0) .render(area, buf); } diff --git a/src/views/result_page.rs b/src/views/result_page.rs index a749416..267add1 100644 --- a/src/views/result_page.rs +++ b/src/views/result_page.rs @@ -15,6 +15,7 @@ pub struct ResultPageState { pub horizontal_scroll: u16, pub horizontal_scroll_state: ScrollbarState, pub ack: bool, + pub animation_frame: u16, } #[derive(Default, Debug)] @@ -37,18 +38,21 @@ impl ResultPage { .content_length(num_lines); state.horizontal_scroll_state = state.horizontal_scroll_state.content_length(max_width); + state.animation_frame = 0; Self { result_text: Paragraph::new(result_text), } } - fn render_left(&self, buf: &mut Buffer, left: Rect) { + fn render_left(&self, buf: &mut Buffer, left: Rect, state: &mut ResultPageState) { let left_block = Block::bordered() .border_type(BorderType::Plain) - .border_style(Style::default().fg(Color::Yellow)); + .border_style(Style::default().fg(Color::Rgb(255, 165, 0))) + .title("GPU MODE") + .title_alignment(Alignment::Center); - let left_text = Paragraph::new(utils::get_ascii_art()); + let left_text = Paragraph::new(utils::get_ascii_art_frame(state.animation_frame / 5)); left_text.block(left_block).render(left, buf); } @@ -56,10 +60,11 @@ impl ResultPage { fn render_right(&self, buf: &mut Buffer, right: Rect, state: &mut ResultPageState) { let right_block = Block::bordered() .border_type(BorderType::Plain) - .border_style(Style::default().fg(Color::Yellow)) + .border_style(Style::default().fg(Color::Rgb(255, 165, 0))) + .title_alignment(Alignment::Center) + .title("Submission Results") .title_bottom("Press q to quit...") - .title_style(Style::default().fg(Color::Red)) - .title_alignment(Alignment::Right); + .title_style(Style::default().fg(Color::Magenta)); let result_text = self .result_text @@ -70,8 +75,9 @@ impl ResultPage { } pub fn handle_key_event(&mut self, state: &mut ResultPageState) { - if event::poll(std::time::Duration::from_millis(50)).unwrap() { - if let Event::Key(key) = event::read().unwrap() { + // Use a non-blocking poll + if let Ok(true) = event::poll(std::time::Duration::from_millis(0)) { + if let Ok(Event::Key(key)) = event::read() { if key.kind != KeyEventKind::Press { return; } @@ -115,10 +121,13 @@ impl StatefulWidget for &ResultPage { type State = ResultPageState; fn render(self, area: Rect, buf: &mut Buffer, state: &mut ResultPageState) { + // Increment animation frame on every render + state.animation_frame = state.animation_frame.wrapping_add(1); + let layout = Layout::horizontal([Constraint::Percentage(45), Constraint::Percentage(55)]); let [left, right] = layout.areas(area); - self.render_left(buf, left); + self.render_left(buf, left, state); self.render_right(buf, right, state); let vertical_scrollbar =