diff --git a/src/ui.rs b/src/ui.rs index f3bb43c..f065f4c 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -1,6 +1,6 @@ use ratatui::prelude::*; use ratatui::widgets::{ - Bar, BarChart, BarGroup, Block, Borders, Gauge, List, ListItem, Paragraph, + Bar, BarChart, BarGroup, Block, Borders, List, ListItem, Paragraph, }; use crate::app::{App, InputMode, Panel}; @@ -13,8 +13,7 @@ pub fn draw(f: &mut Frame, app: &mut App) { .constraints([ Constraint::Min(1), Constraint::Length(6), // эквалайзер - Constraint::Length(3), // прогресс - Constraint::Length(3), // статус + vol + Constraint::Length(3), // статус + время + mode + vol ]) .split(f.area()); @@ -26,8 +25,7 @@ pub fn draw(f: &mut Frame, app: &mut App) { draw_left_panel(f, app, top[0]); draw_right_panel(f, app, top[1]); draw_equalizer(f, app, chunks[1]); - draw_progress(f, app, chunks[2]); - draw_status(f, app, chunks[3]); + draw_status(f, app, chunks[2]); } fn draw_left_panel(f: &mut Frame, app: &mut App, area: Rect) { @@ -44,7 +42,6 @@ fn draw_left_panel(f: &mut Frame, app: &mut App, area: Rect) { Style::default().add_modifier(Modifier::DIM) }; - // Обновляем selected в сохранённом состоянии (не создаём новый ListState) let sel = if app.library.artists.is_empty() { None } else { @@ -140,7 +137,6 @@ fn draw_right_panel(f: &mut Frame, app: &mut App, area: Rect) { }) .collect(); - // Заголовок с индикатором активного фильтра let title = match app.library.sort_mode { SortMode::ByArtist => { let artist_name = app @@ -188,11 +184,10 @@ fn draw_right_panel(f: &mut Frame, app: &mut App, area: Rect) { f.render_stateful_widget(list, area, &mut app.library.right_state); } -/// Цветной эквалайзер: 32 столбика с градиентом от синего к красному fn draw_equalizer(f: &mut Frame, app: &App, area: Rect) { let bars_data = app.player.spectrum.bars(); let num_bars = 32; - + let mut display: Vec = Vec::with_capacity(num_bars); for i in 0..num_bars { let a = bars_data[i * 2]; @@ -239,41 +234,20 @@ fn draw_equalizer(f: &mut Frame, app: &App, area: Rect) { f.render_widget(chart, area); } -fn draw_progress(f: &mut Frame, app: &App, area: Rect) { - let (pos, total) = app.progress(); - let ratio = if total.as_secs_f64() > 0.0 { - (pos.as_secs_f64() / total.as_secs_f64()).clamp(0.0, 1.0) - } else { - 0.0 - }; - - let gauge = Gauge::default() - .block(Block::default().borders(Borders::ALL).title(" Прогресс ")) - .gauge_style(Style::default().fg(Color::Rgb(70, 130, 180))) - .ratio(ratio) - .label(format!( - "{:02}:{:02} / {:02}:{:02}", - pos.as_secs() / 60, - pos.as_secs() % 60, - total.as_secs() / 60, - total.as_secs() % 60, - )); - - f.render_widget(gauge, area); -} - fn draw_status(f: &mut Frame, app: &App, area: Rect) { + // Раскладка нижней строки: + // [ Статус ................. ] [ 01:23 / 03:45 ] [ Mode ] [ vol: NN% ] let inner = Layout::default() .direction(Direction::Horizontal) .constraints([ Constraint::Min(1), + Constraint::Length(18), Constraint::Length(16), Constraint::Length(12), ]) .split(area); - // Если поиск активен — показываем строку ввода. - // Иначе — статус с индикатором паузы. + // ── Статус / поиск / пауза ──────────────────────────────── let (status_text, status_title) = if app.input_mode == InputMode::Search { (format!("> {}", app.search_buffer), " Поиск ") } else { @@ -285,6 +259,22 @@ fn draw_status(f: &mut Frame, app: &App, area: Rect) { .block(Block::default().borders(Borders::ALL).title(status_title)); f.render_widget(status, inner[0]); + // ── Время: текущее / полное ─────────────────────────────── + let (pos, total) = app.progress(); + let time_text = format!( + "{:02}:{:02} / {:02}:{:02}", + pos.as_secs() / 60, + pos.as_secs() % 60, + total.as_secs() / 60, + total.as_secs() % 60, + ); + let time = Paragraph::new(time_text) + .alignment(Alignment::Center) + .style(Style::default().fg(Color::Rgb(70, 130, 180))) + .block(Block::default().borders(Borders::ALL).title(" Время ")); + f.render_widget(time, inner[1]); + + // ── Repeat / Shuffle ────────────────────────────────────── let mode_str = match (app.repeat, app.shuffle) { (RepeatMode::Off, false) => "".to_string(), (RepeatMode::Off, true) => "SHUF".to_string(), @@ -296,11 +286,12 @@ fn draw_status(f: &mut Frame, app: &App, area: Rect) { let mode = Paragraph::new(mode_str) .alignment(Alignment::Center) .block(Block::default().borders(Borders::ALL).title(" Mode ")); - f.render_widget(mode, inner[1]); + f.render_widget(mode, inner[2]); - let vol_text = format!("Vol: {}%", (app.player.volume() * 100.0) as u32); + // ── Громкость ───────────────────────────────────────────── + let vol_text = format!("vol: {}%", (app.player.volume() * 100.0) as u32); let vol = Paragraph::new(vol_text) .alignment(Alignment::Center) - .block(Block::default().borders(Borders::ALL).title(" ")); - f.render_widget(vol, inner[2]); + .block(Block::default().borders(Borders::ALL).title(" Звук ")); + f.render_widget(vol, inner[3]); } \ No newline at end of file