add keymaps to readme.md and minor changes
This commit is contained in:
parent
00c5c12d82
commit
a8161521d0
22
README.md
22
README.md
|
|
@ -1,4 +1,24 @@
|
|||
A MPD client in Rust
|
||||
|
||||
# Keys
|
||||
### Keys
|
||||
- 'q' OR 'Ctr+C' to quit
|
||||
- 'p' to toggle pause
|
||||
- '+' to increase volume
|
||||
- '-' to decrease volume
|
||||
- 'D' to get dmenu prompt
|
||||
- 'j' to scroll down
|
||||
- 'k' to scroll up
|
||||
- 'l' add song to playlist or go inside the directory
|
||||
- 'h' to go back to previous directory
|
||||
- `Tab` to cycle through tabs
|
||||
- '1' to go to directory tree
|
||||
- '2' to go to current playing queue
|
||||
- '3' to go to playlists view
|
||||
- 'Enter' to add song/playlist to current playlist
|
||||
- 'a' to append the song to current playing queue
|
||||
- 'f' to go forward
|
||||
- 'b' to go backwords
|
||||
- '>' to play next song from queue
|
||||
- '<' to play previous song from queue
|
||||
- 'U' to update the MPD database
|
||||
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ impl App {
|
|||
pub fn tick(&mut self) {
|
||||
self.conn.update_state();
|
||||
self.conn.update_progress();
|
||||
self.conn.update_volume();
|
||||
self.update_queue();
|
||||
self.browser.update_directory(&mut self.conn).unwrap();
|
||||
}
|
||||
|
|
@ -97,7 +98,6 @@ impl App {
|
|||
|
||||
pub fn get_playlist(conn: &mut Client) -> AppResult<Vec<String>> {
|
||||
let list: Vec<String> = conn.playlists()?.iter().map(|p| p.clone().name).collect();
|
||||
|
||||
Ok(list)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
use mpd::Query;
|
||||
|
||||
use crate::{app::AppResult, connection::Connection};
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ pub struct Connection {
|
|||
pub state: String,
|
||||
pub elapsed: Duration,
|
||||
pub total_duration: Duration,
|
||||
pub volume: u8,
|
||||
}
|
||||
|
||||
impl Connection {
|
||||
|
|
@ -26,8 +27,8 @@ impl Connection {
|
|||
.into_iter()
|
||||
.map(|x| x.file)
|
||||
.collect();
|
||||
|
||||
let (elapsed, total) = conn.status().unwrap().time.unwrap_or_default();
|
||||
let volume: u8 = conn.status().unwrap_or_default().volume as u8;
|
||||
|
||||
Ok(Self {
|
||||
conn,
|
||||
|
|
@ -35,6 +36,7 @@ impl Connection {
|
|||
state: "Stopped".to_string(),
|
||||
elapsed,
|
||||
total_duration: total,
|
||||
volume,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -77,6 +79,10 @@ impl Connection {
|
|||
self.total_duration = total;
|
||||
}
|
||||
|
||||
pub fn update_volume(&mut self) {
|
||||
self.volume = self.conn.status().unwrap_or_default().volume as u8;
|
||||
}
|
||||
|
||||
pub fn get_progress_ratio(&self) -> f64 {
|
||||
let total = self.total_duration.as_secs_f64();
|
||||
if total == 0.0 {
|
||||
|
|
@ -84,7 +90,7 @@ impl Connection {
|
|||
} else {
|
||||
let ratio = self.elapsed.as_secs_f64() / self.total_duration.as_secs_f64();
|
||||
if ratio > 1.0 || ratio == 0.0 {
|
||||
1.0
|
||||
0.0
|
||||
} else {
|
||||
ratio
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@ use std::time::Duration;
|
|||
|
||||
use crate::app::{App, AppResult, SelectedTab};
|
||||
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
|
||||
use mpd::{Query, Term};
|
||||
use ratatui::style::Modifier;
|
||||
use rust_fuzzy_search;
|
||||
use simple_dmenu::dmenu;
|
||||
|
||||
|
|
@ -13,6 +11,8 @@ pub fn handle_key_events(key_event: KeyEvent, app: &mut App) -> AppResult<()> {
|
|||
KeyCode::Char('c') | KeyCode::Char('C') => {
|
||||
if key_event.modifiers == KeyModifiers::CONTROL {
|
||||
app.quit();
|
||||
} else {
|
||||
app.conn.conn.clear()?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -68,12 +68,6 @@ pub fn handle_key_events(key_event: KeyEvent, app: &mut App) -> AppResult<()> {
|
|||
app.conn.pause();
|
||||
}
|
||||
|
||||
// Clear Queue
|
||||
KeyCode::Char('x') => {
|
||||
app.conn.conn.clear()?;
|
||||
// app.update_queue();
|
||||
}
|
||||
|
||||
// Dmenu prompt
|
||||
KeyCode::Char('D') => {
|
||||
app.conn.play_dmenu()?;
|
||||
|
|
@ -122,22 +116,23 @@ pub fn handle_key_events(key_event: KeyEvent, app: &mut App) -> AppResult<()> {
|
|||
app.selected_tab = SelectedTab::Playlists;
|
||||
}
|
||||
|
||||
|
||||
KeyCode::Char('n') => {
|
||||
KeyCode::Char('>') => {
|
||||
app.conn.conn.next()?;
|
||||
}
|
||||
|
||||
KeyCode::Char('N') => {
|
||||
KeyCode::Char('<') => {
|
||||
app.conn.conn.prev()?;
|
||||
}
|
||||
|
||||
// Volume controls
|
||||
KeyCode::Char('=') => {
|
||||
app.conn.inc_volume(2);
|
||||
app.conn.update_volume();
|
||||
}
|
||||
|
||||
KeyCode::Char('-') => {
|
||||
app.conn.dec_volume(2);
|
||||
app.conn.update_volume();
|
||||
}
|
||||
|
||||
// Delete highlighted song from the queue
|
||||
|
|
|
|||
120
src/ui.rs
120
src/ui.rs
|
|
@ -1,7 +1,4 @@
|
|||
use crate::{
|
||||
app::{App, AppResult, SelectedTab},
|
||||
browser::FileBrowser,
|
||||
};
|
||||
use crate::app::{App, SelectedTab};
|
||||
use ratatui::{
|
||||
prelude::*,
|
||||
widgets::{block::Title, *},
|
||||
|
|
@ -17,73 +14,62 @@ pub fn render(app: &mut App, frame: &mut Frame) {
|
|||
// Layout
|
||||
let layout = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints(vec![
|
||||
Constraint::Percentage(0),
|
||||
// Constraint::Percentage(88),
|
||||
Constraint::Percentage(93),
|
||||
Constraint::Percentage(7),
|
||||
])
|
||||
.constraints(vec![Constraint::Percentage(93), Constraint::Percentage(7)])
|
||||
.split(frame.size());
|
||||
//
|
||||
// let outer_layout = Layout::default()
|
||||
// .direction(Direction::Horizontal)
|
||||
// .constraints(vec![Constraint::Percentage(50), Constraint::Percentage(50)])
|
||||
// .split(main_layout[1]);
|
||||
//
|
||||
// let inner_layout = Layout::default()
|
||||
// .direction(Direction::Vertical)
|
||||
// .constraints(vec![Constraint::Percentage(50), Constraint::Percentage(50)])
|
||||
// .split(outer_layout[1]);
|
||||
|
||||
// draw_song_list(frame, app, outer_layout[0]);
|
||||
// draw_queue(frame, app, inner_layout[0]);
|
||||
// draw_playlists(frame, app, inner_layout[1]);
|
||||
draw_progress_bar(frame, app, layout[2]);
|
||||
|
||||
// let highlight_style = (Color::default(), tailwind::YELLOW.c700);
|
||||
// let tab = Tabs::new(vec!["Songs List", "Play Queue", "Playlists"])
|
||||
// .block(Block::default().title("Tabs").borders(Borders::ALL))
|
||||
// .style(Style::default().white())
|
||||
// .highlight_style(highlight_style)
|
||||
// .divider(" ")
|
||||
// .select(app.selected_tab.clone() as usize)
|
||||
// .padding("", "");
|
||||
// frame.render_widget(tab, layout[0]);
|
||||
|
||||
match app.selected_tab {
|
||||
// SelectedTab::SongList => draw_song_list(frame, app, layout[1]),
|
||||
SelectedTab::Queue => draw_queue(frame, app, layout[1]),
|
||||
SelectedTab::Playlists => draw_playlists(frame, app, layout[1]),
|
||||
SelectedTab::DirectoryBrowser => draw_directory_browser(frame, app, layout[1]),
|
||||
}
|
||||
SelectedTab::Queue => draw_queue(frame, app, layout[0]),
|
||||
SelectedTab::Playlists => draw_playlists(frame, app, layout[0]),
|
||||
SelectedTab::DirectoryBrowser => draw_directory_browser(frame, app, layout[0]),
|
||||
}
|
||||
|
||||
/// draws list of songs
|
||||
fn draw_song_list(frame: &mut Frame, app: &mut App, size: Rect) {
|
||||
draw_progress_bar(frame, app, layout[1]);
|
||||
}
|
||||
|
||||
/// Draws the file tree browser
|
||||
fn draw_directory_browser(frame: &mut Frame, app: &mut App, size: Rect) {
|
||||
let mut song_state = ListState::default();
|
||||
let total_songs = app.conn.conn.stats().unwrap().songs.to_string();
|
||||
let list = List::new(app.conn.songs_filenames.clone())
|
||||
let mut list: Vec<String> = vec![];
|
||||
for (t, s) in app.browser.filetree.iter() {
|
||||
if t == "file" {
|
||||
list.push(s.to_string());
|
||||
} else {
|
||||
list.push(format!("[{}]", *s));
|
||||
}
|
||||
}
|
||||
let list = List::new(list)
|
||||
.block(
|
||||
Block::default()
|
||||
.title("Song List".green().bold())
|
||||
.title(format!("File Browser: {}", app.browser.path.clone()).bold())
|
||||
.title(
|
||||
Title::from(format!("Total Songs: {}", total_songs).bold().green())
|
||||
.alignment(Alignment::Center),
|
||||
)
|
||||
.title(
|
||||
Title::from(format!("Volume: {}%", app.conn.volume).bold().green())
|
||||
.alignment(Alignment::Right),
|
||||
)
|
||||
.borders(Borders::ALL),
|
||||
)
|
||||
.highlight_style(Style::new().add_modifier(Modifier::REVERSED))
|
||||
.highlight_symbol(">>")
|
||||
.repeat_highlight_symbol(true);
|
||||
.repeat_highlight_symbol(true)
|
||||
.scroll_padding(20);
|
||||
|
||||
song_state.select(Some(app.song_list.index));
|
||||
song_state.select(Some(app.browser.selected));
|
||||
frame.render_stateful_widget(list, size, &mut song_state);
|
||||
}
|
||||
|
||||
/// draws playing queue
|
||||
fn draw_queue(frame: &mut Frame, app: &mut App, size: Rect) {
|
||||
let mut queue_state = ListState::default();
|
||||
let title = Block::default().title(Title::from("Play Queue".green().bold()));
|
||||
let title = Block::default()
|
||||
.title(Title::from("Play Queue".green().bold()))
|
||||
.title(
|
||||
Title::from(format!("Volume: {}%", app.conn.volume).bold().green())
|
||||
.alignment(Alignment::Right),
|
||||
);
|
||||
let list = List::new(app.queue_list.list.clone())
|
||||
.block(title.borders(Borders::ALL))
|
||||
.highlight_style(Style::new().add_modifier(Modifier::REVERSED))
|
||||
|
|
@ -98,7 +84,13 @@ fn draw_queue(frame: &mut Frame, app: &mut App, size: Rect) {
|
|||
fn draw_playlists(frame: &mut Frame, app: &mut App, size: Rect) {
|
||||
let mut state = ListState::default();
|
||||
|
||||
let title = Block::default().title(Title::from("Playlist".green().bold()));
|
||||
let title = Block::default()
|
||||
.title(Title::from("Playlist".green().bold()))
|
||||
.title(
|
||||
Title::from(format!("Volume: {}%", app.conn.volume).bold().green())
|
||||
.alignment(Alignment::Right),
|
||||
);
|
||||
|
||||
let list = List::new(app.pl_list.list.clone())
|
||||
.block(title.borders(Borders::ALL))
|
||||
.highlight_style(Style::new().add_modifier(Modifier::REVERSED))
|
||||
|
|
@ -109,7 +101,7 @@ fn draw_playlists(frame: &mut Frame, app: &mut App, size: Rect) {
|
|||
frame.render_stateful_widget(list, size, &mut state);
|
||||
}
|
||||
|
||||
// Progress Bar
|
||||
/// Draws Progress Bar
|
||||
fn draw_progress_bar(frame: &mut Frame, app: &mut App, size: Rect) {
|
||||
let song = app
|
||||
.conn
|
||||
|
|
@ -151,33 +143,3 @@ fn draw_progress_bar(frame: &mut Frame, app: &mut App, size: Rect) {
|
|||
|
||||
frame.render_widget(progress_bar, size);
|
||||
}
|
||||
|
||||
fn draw_directory_browser(frame: &mut Frame, app: &mut App, size: Rect) {
|
||||
let mut song_state = ListState::default();
|
||||
let total_songs = app.conn.conn.stats().unwrap().songs.to_string();
|
||||
let mut list: Vec<String> = vec![];
|
||||
for (t, s) in app.browser.filetree.iter() {
|
||||
if t == "file" {
|
||||
list.push(s.to_string());
|
||||
} else {
|
||||
list.push(format!("[{}]", *s));
|
||||
}
|
||||
}
|
||||
let list = List::new(list)
|
||||
.block(
|
||||
Block::default()
|
||||
.title(format!("File Browser: {}", app.browser.path.clone()).bold())
|
||||
.title(
|
||||
Title::from(format!("Total Songs: {}", total_songs).bold().green())
|
||||
.alignment(Alignment::Right),
|
||||
)
|
||||
.borders(Borders::ALL),
|
||||
)
|
||||
.highlight_style(Style::new().add_modifier(Modifier::REVERSED))
|
||||
.highlight_symbol(">>")
|
||||
.repeat_highlight_symbol(true)
|
||||
.scroll_padding(20);
|
||||
|
||||
song_state.select(Some(app.browser.selected));
|
||||
frame.render_stateful_widget(list, size, &mut song_state);
|
||||
}
|
||||
|
|
|
|||
Reference in New Issue