обновление

This commit is contained in:
2026-10-15 15:54:31 +02:00
parent 4c7f46e105
commit 07baff09c4
9 changed files with 571 additions and 196 deletions

119
src/ui.rs
View File

@@ -1,6 +1,6 @@
use ratatui::prelude::*;
use ratatui::widgets::{
Bar, BarChart, BarGroup, Block, Borders, List, ListItem, Paragraph,
Bar, BarChart, BarGroup, Block, Borders, Clear, List, ListItem, Paragraph,
};
use crate::app::{App, InputMode, Panel};
@@ -26,9 +26,15 @@ pub fn draw(f: &mut Frame, app: &mut App) {
draw_right_panel(f, app, top[1]);
draw_equalizer(f, app, chunks[1]);
draw_status(f, app, chunks[2]);
if app.show_help {
draw_help(f, f.area());
}
}
fn draw_left_panel(f: &mut Frame, app: &mut App, area: Rect) {
f.render_widget(Clear, area);
let items: Vec<ListItem> = app
.library
.artists
@@ -49,8 +55,14 @@ fn draw_left_panel(f: &mut Frame, app: &mut App, area: Rect) {
};
app.library.left_state.select(sel);
let title = match app.library.sort_mode {
SortMode::ByArtist => " Исполнители ",
SortMode::ByAlbum => " Альбомы ",
SortMode::ByFilename => " Источник ",
};
let list = List::new(items)
.block(Block::default().borders(Borders::ALL).title(" Исполнители "))
.block(Block::default().borders(Borders::ALL).title(title))
.highlight_style(highlight)
.highlight_symbol("> ");
@@ -66,6 +78,8 @@ fn fmt_dur(d: std::time::Duration) -> String {
}
fn draw_right_panel(f: &mut Frame, app: &mut App, area: Rect) {
f.render_widget(Clear, area);
let rows = app.library.current_right_rows();
let items: Vec<ListItem> = rows
@@ -137,20 +151,31 @@ fn draw_right_panel(f: &mut Frame, app: &mut App, area: Rect) {
})
.collect();
let selected_name = app
.library
.artists
.get(app.library.artist_selected)
.map(|a| a.name.as_str())
.unwrap_or("—");
let title = match app.library.sort_mode {
SortMode::ByArtist => {
let artist_name = app
.library
.artists
.get(app.library.artist_selected)
.map(|a| a.name.as_str())
.unwrap_or("—");
if app.library.filter.is_empty() {
format!(" Альбомы и треки — {} ", artist_name)
format!(" Альбомы и треки — {} ", selected_name)
} else {
format!(
" Альбомы и треки — {} [{}] ",
artist_name, app.library.filter
selected_name, app.library.filter
)
}
}
SortMode::ByAlbum => {
if app.library.filter.is_empty() {
format!(" Исполнители и треки — {} ", selected_name)
} else {
format!(
" Исполнители и треки — {} [{}] ",
selected_name, app.library.filter
)
}
}
@@ -235,8 +260,6 @@ fn draw_equalizer(f: &mut Frame, app: &App, area: Rect) {
}
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([
@@ -247,7 +270,6 @@ fn draw_status(f: &mut Frame, app: &App, area: Rect) {
])
.split(area);
// ── Статус / поиск / пауза ────────────────────────────────
let (status_text, status_title) = if app.input_mode == InputMode::Search {
(format!("> {}", app.search_buffer), " Поиск ")
} else {
@@ -259,7 +281,6 @@ 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}",
@@ -270,11 +291,9 @@ fn draw_status(f: &mut Frame, app: &App, area: Rect) {
);
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(),
@@ -288,10 +307,74 @@ fn draw_status(f: &mut Frame, app: &App, area: Rect) {
.block(Block::default().borders(Borders::ALL).title(" Mode "));
f.render_widget(mode, inner[2]);
// ── Громкость ─────────────────────────────────────────────
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(" Звук "));
.block(Block::default().borders(Borders::ALL).title(" "));
f.render_widget(vol, inner[3]);
}
fn draw_help(f: &mut Frame, screen: Rect) {
let width = 60u16.min(screen.width.saturating_sub(4));
let height = 34u16.min(screen.height.saturating_sub(4));
let x = (screen.width.saturating_sub(width)) / 2;
let y = (screen.height.saturating_sub(height)) / 2;
let area = Rect::new(x, y, width, height);
f.render_widget(Clear, area);
let header = Style::default()
.fg(Color::Yellow)
.add_modifier(Modifier::BOLD);
let title_color = Style::default().fg(Color::Rgb(100, 149, 237));
let help_text = vec![
Line::from(Span::styled(
" Управление плеером ",
title_color.add_modifier(Modifier::BOLD),
)),
Line::from(""),
Line::from(Span::styled(" Навигация", header)),
Line::from(" w / ↑ вверх по списку"),
Line::from(" s / ↓ вниз по списку"),
Line::from(" Tab переключить панель"),
Line::from(" g / G в начало / в конец списка"),
Line::from(" f к играющему треку"),
Line::from(""),
Line::from(Span::styled(" Воспроизведение", header)),
Line::from(" Enter играть выделенный трек"),
Line::from(" Space пауза / продолжить"),
Line::from(" z стоп"),
Line::from(" Ctrl+→ / Ctrl+d следующий трек"),
Line::from(" Ctrl+← / Ctrl+a предыдущий трек"),
Line::from(" r repeat: off → all → one"),
Line::from(" x shuffle вкл/выкл"),
Line::from(""),
Line::from(Span::styled(" Перемотка", header)),
Line::from(" a / ← −5 секунд"),
Line::from(" d / → +5 секунд"),
Line::from(" 1..9 перейти к 10%..90% трека"),
Line::from(""),
Line::from(Span::styled(" Звук и прочее", header)),
Line::from(" + / - громкость"),
Line::from(" / поиск"),
Line::from(" t сортировка: артист → альбом → файл"),
Line::from(" F1 эта справка"),
Line::from(" q / Esc выход"),
Line::from(""),
Line::from(Span::styled(
" F1 или Esc — закрыть ",
Style::default().fg(Color::DarkGray),
)),
];
let help = Paragraph::new(help_text).block(
Block::default()
.borders(Borders::ALL)
.border_style(title_color)
.title(" Помощь "),
);
f.render_widget(help, area);
}