обновление

This commit is contained in:
2026-10-13 17:38:18 +02:00
parent 255a99ed0f
commit 08a8a7cce5
6 changed files with 502 additions and 87 deletions

130
src/ui.rs
View File

@@ -1,7 +1,8 @@
use ratatui::prelude::*;
use ratatui::widgets::{Block, Borders, Gauge, List, ListItem, Paragraph};
use crate::app::App;
use crate::app::{App, Panel};
use crate::library::{LeftRow, SortMode};
pub fn draw(f: &mut Frame, app: &mut App) {
let chunks = Layout::default()
@@ -14,29 +15,114 @@ pub fn draw(f: &mut Frame, app: &mut App) {
])
.split(f.area());
draw_track_list(f, app, chunks[0]);
// Горизонтальное разделение верхней области: 40% слева, 60% справа
let top = Layout::default()
.direction(Direction::Horizontal)
.constraints([Constraint::Percentage(40), Constraint::Percentage(60)])
.split(chunks[0]);
draw_left_panel(f, app, top[0]);
draw_right_panel(f, app, top[1]);
draw_progress(f, app, chunks[1]);
draw_volume(f, app, chunks[2]);
draw_status(f, app, chunks[3]);
}
fn draw_track_list(f: &mut Frame, app: &mut App, area: Rect) {
fn draw_left_panel(f: &mut Frame, app: &App, area: Rect) {
let items: Vec<ListItem> = app
.tracks
.library
.left_rows
.iter()
.enumerate()
.map(|(i, t)| {
let marker = if Some(i) == app.playing_index { "♪ " } else { " " };
ListItem::new(format!("{}{} - {}", marker, t.artist, t.title))
.map(|row| match row {
LeftRow::Artist { name } => ListItem::new(Line::from(vec![
Span::styled("▶ ", Style::default().fg(Color::Yellow)),
Span::styled(
name.clone(),
Style::default()
.fg(Color::Yellow)
.add_modifier(Modifier::BOLD),
),
])),
LeftRow::Album { name } => ListItem::new(Line::from(vec![
Span::raw(" "),
Span::styled(name.clone(), Style::default().fg(Color::Cyan)),
])),
})
.collect();
let title = match app.library.sort_mode {
SortMode::ByArtist => " Артисты / Альбомы ",
SortMode::ByFilename => " Источник ",
};
let highlight = if app.active_panel == Panel::Left {
Style::default().add_modifier(Modifier::REVERSED)
} else {
Style::default().add_modifier(Modifier::DIM)
};
let mut list_state = ratatui::widgets::ListState::default();
if !app.library.left_rows.is_empty() {
list_state.select(Some(app.library.left_selected));
}
let list = List::new(items)
.block(Block::default().borders(Borders::ALL).title(" Треки "))
.highlight_style(Style::default().add_modifier(Modifier::REVERSED))
.block(Block::default().borders(Borders::ALL).title(title))
.highlight_style(highlight)
.highlight_symbol("> ");
f.render_stateful_widget(list, area, &mut app.list_state);
f.render_stateful_widget(list, area, &mut list_state);
}
fn draw_right_panel(f: &mut Frame, app: &App, area: Rect) {
let indices = app.library.current_right_indices();
let items: Vec<ListItem> = indices
.iter()
.map(|&idx| {
let is_playing = Some(idx) == app.playing_index;
let marker = if is_playing { "♪ " } else { " " };
let (title, num) = match app.library.track(idx) {
Some(t) => (
t.title.clone(),
t.track_number
.map(|n| format!("{:02}. ", n))
.unwrap_or_default(),
),
None => ("<unknown>".into(), String::new()),
};
let style = if is_playing {
Style::default().fg(Color::Green)
} else {
Style::default()
};
ListItem::new(Line::from(vec![
Span::raw(marker),
Span::styled(format!("{}{}", num, title), style),
]))
})
.collect();
let highlight = if app.active_panel == Panel::Right {
Style::default().add_modifier(Modifier::REVERSED)
} else {
Style::default().add_modifier(Modifier::DIM)
};
let mut list_state = ratatui::widgets::ListState::default();
if !indices.is_empty() {
list_state.select(Some(app.library.right_selected));
}
let list = List::new(items)
.block(Block::default().borders(Borders::ALL).title(" Треки "))
.highlight_style(highlight)
.highlight_symbol("> ");
f.render_stateful_widget(list, area, &mut list_state);
}
fn draw_progress(f: &mut Frame, app: &App, area: Rect) {
@@ -53,8 +139,10 @@ fn draw_progress(f: &mut Frame, app: &App, area: Rect) {
.ratio(ratio)
.label(format!(
"{:02}:{:02} / {:02}:{:02}",
pos.as_secs() / 60, pos.as_secs() % 60,
total.as_secs() / 60, total.as_secs() % 60,
pos.as_secs() / 60,
pos.as_secs() % 60,
total.as_secs() / 60,
total.as_secs() % 60,
));
f.render_widget(gauge, area);
@@ -63,12 +151,20 @@ fn draw_progress(f: &mut Frame, app: &App, area: Rect) {
fn draw_volume(f: &mut Frame, app: &App, area: Rect) {
let vol = app.player.volume();
let ratio = (vol as f64 / 2.0).clamp(0.0, 1.0);
let color = if vol > 1.0 { Color::Yellow }
else if vol > 0.5 { Color::Cyan }
else { Color::Blue };
let color = if vol > 1.0 {
Color::Yellow
} else if vol > 0.5 {
Color::Cyan
} else {
Color::Blue
};
let gauge = Gauge::default()
.block(Block::default().borders(Borders::ALL).title(" Громкость (+/-) "))
.block(
Block::default()
.borders(Borders::ALL)
.title(" Громкость (+/-) "),
)
.gauge_style(Style::default().fg(color))
.ratio(ratio)
.label(format!("{}%", (vol * 100.0) as u32));