Compare commits

..

No commits in common. "master" and "v0.1.4" have entirely different histories.

19 changed files with 69 additions and 295 deletions

View File

@ -1,4 +0,0 @@
## rmptui-v0.1.6
- Add songs to new playlist feature
- Code refactoring
- fix #9

2
Cargo.lock generated
View File

@ -282,7 +282,7 @@ dependencies = [
[[package]]
name = "rmptui"
version = "0.1.6"
version = "0.1.4"
dependencies = [
"crossterm",
"mpd",

View File

@ -5,7 +5,7 @@ description = """
a fast and minimal tui mpd client
"""
readme = "README.md"
version = "0.1.6"
version = "0.1.4"
edition = "2021"
repository = "https://github.com/krolyxon/rmptui"
keywords = ["rmptui", "mpd", "music", "cli", "tui", "client"]

0
LICENSE Normal file → Executable file
View File

3
README.md Normal file → Executable file
View File

@ -15,7 +15,6 @@ rmptui is a minimal tui mpd client made with rust.
| `p` | Toggle pause |
| `+`/`=` | Increase volume |
| `-` | Decrease volume |
| `m` | Toggle Mute |
| `D` | Get dmenu prompt |
| `j`/`Down` | Scroll down |
| `k`/`Up` | Scroll up |
@ -38,7 +37,6 @@ rmptui is a minimal tui mpd client made with rust.
| `r` | Toggle repeat |
| `z` | Toggle random |
| `/` | Search |
| `R` | Rename Playlist |
| `g` | Go to top of list |
| `G` | Go to bottom of list |
@ -55,5 +53,4 @@ rmptui is a minimal tui mpd client made with rust.
- [x] metadata based tree view
- [x] view playlist
- [x] change playlist name
- [x] add to new playlist
- [ ] add lyrics fetcher

View File

@ -1,12 +1,11 @@
use std::{path::Path, time::Duration};
use crate::browser::FileBrowser;
use crate::utils::FileExtension;
use crate::connection::Connection;
use crate::list::ContentList;
use crate::ui::InputMode;
use crate::utils::FileExtension;
use mpd::{Client, Song};
use ratatui::widgets::{ListState, TableState};
// Application result type
pub type AppResult<T> = std::result::Result<T, Box<dyn std::error::Error>>;
@ -25,14 +24,9 @@ pub struct App {
pub inputmode: InputMode, // Defines input mode, Normal or Search
pub search_input: String, // Stores the userinput to be searched
pub search_cursor_pos: usize, // Stores the cursor position for searching
pub pl_newname_input: String, // Stores the new name of the playlist
pub pl_cursor_pos: usize, // Stores the cursor position for renaming playlist
pub pl_new_pl_input: String, // Stores the name of new playlist to be created
pub pl_new_pl_cursor_pos: usize, // Stores the cursor position of new playlist to be created
pub pl_new_pl_songs_buffer: Vec<Song>, // Buffer for songs that need to be added to the newly created playlist
// playlist variables
// used to show playlist popup
pub playlist_popup: bool,
@ -40,11 +34,6 @@ pub struct App {
// Determines if the database should be updated or not
pub should_update_song_list: bool,
// States
pub queue_state: TableState,
pub browser_state: TableState,
pub playlists_state: ListState,
}
#[derive(Debug, PartialEq, Clone)]
@ -68,10 +57,6 @@ impl App {
let browser = FileBrowser::new();
let queue_state = TableState::new();
let browser_state = TableState::new();
let playlists_state = ListState::default();
Ok(Self {
running: true,
conn,
@ -85,14 +70,8 @@ impl App {
search_cursor_pos: 0,
pl_cursor_pos: 0,
playlist_popup: false,
pl_new_pl_input: String::new(),
pl_new_pl_cursor_pos: 0,
pl_new_pl_songs_buffer: Vec::new(),
append_list,
should_update_song_list: false,
queue_state,
browser_state,
playlists_state,
})
}
@ -101,7 +80,8 @@ impl App {
self.update_queue();
// Deals with database update
if self.should_update_song_list && self.conn.status.updating_db.is_none() {
if self.should_update_song_list {
if let None = self.conn.status.updating_db {
// Update the songs list
self.conn.songs_filenames = self
.conn
@ -114,6 +94,7 @@ impl App {
self.browser.update_directory(&mut self.conn)?;
self.should_update_song_list = false;
}
}
Ok(())
@ -143,7 +124,6 @@ impl App {
pub fn get_append_list(conn: &mut Client) -> AppResult<ContentList<String>> {
let mut list = ContentList::new();
list.list.push("Current Playlist".to_string());
list.list.push("New Playlist".to_string());
for item in Self::get_playlist(conn)? {
list.list.push(item.to_string());
}
@ -161,22 +141,22 @@ impl App {
let file = format!("{}/{}", self.browser.path, content);
let songs = self.conn.conn.listfiles(&file).unwrap_or_default();
for (t, f) in songs.iter() {
if t == "file"
&& Path::new(&f).has_extension(&[
if t == "file" {
if Path::new(&f).has_extension(&[
"mp3", "ogg", "flac", "m4a", "wav", "aac", "opus", "ape", "wma",
"mpc", "aiff", "dff", "mp2", "mka",
])
{
let path = file.clone() + "/" + f;
let full_path = path.strip_prefix("./").unwrap_or("");
let song = self.conn.get_song_with_only_filename(full_path);
self.conn.conn.push(&song)?;
]) {
let path = file.clone() + "/" + f;
let full_path = path.strip_prefix("./").unwrap_or_else(|| "");
let song = self.conn.get_song_with_only_filename(&full_path);
self.conn.conn.push(&song)?;
}
}
}
} else if content_type == "file" {
let mut status = false;
for (i, song) in self.queue_list.list.clone().iter().enumerate() {
let song_path = song.file.split('/').last().unwrap_or_default();
let song_path = song.file.split("/").last().unwrap_or_default();
if song_path.eq(content) {
self.conn.conn.delete(i as u32).unwrap();
status = true;
@ -251,7 +231,7 @@ impl App {
let (t, path) = browser.filetree.get(browser.selected).unwrap();
if t == "directory" {
if path != "." {
browser.prev_path.clone_from(&browser.path);
browser.prev_path = browser.path.clone();
browser.path = browser.prev_path.clone() + "/" + path;
browser.update_directory(&mut self.conn)?;
browser.prev_selected = browser.selected;
@ -259,7 +239,7 @@ impl App {
}
} else {
let index = self.queue_list.list.iter().position(|x| {
let file = x.file.split('/').last().unwrap_or_default();
let file = x.file.split("/").last().unwrap_or_default();
file.eq(path)
});
@ -293,10 +273,6 @@ impl App {
let cursor_moved_left = self.search_cursor_pos.saturating_sub(1);
self.search_cursor_pos = self.clamp_cursor(cursor_moved_left);
}
InputMode::NewPlaylist => {
let cursor_moved_left = self.pl_new_pl_cursor_pos.saturating_sub(1);
self.pl_new_pl_cursor_pos = self.clamp_cursor(cursor_moved_left);
}
_ => {}
}
}
@ -311,12 +287,6 @@ impl App {
let cursor_moved_right = self.search_cursor_pos.saturating_add(1);
self.search_cursor_pos = self.clamp_cursor(cursor_moved_right);
}
InputMode::NewPlaylist => {
let cursor_moved_right = self.pl_new_pl_cursor_pos.saturating_add(1);
self.pl_new_pl_cursor_pos = self.clamp_cursor(cursor_moved_right);
}
_ => {}
}
}
@ -325,24 +295,19 @@ impl App {
match self.inputmode {
InputMode::PlaylistRename => {
self.pl_newname_input.insert(self.pl_cursor_pos, new_char);
}
InputMode::NewPlaylist => {
self.pl_new_pl_input
.insert(self.pl_new_pl_cursor_pos, new_char);
self.move_cursor_right();
}
InputMode::Editing => {
self.search_input.insert(self.search_cursor_pos, new_char);
self.move_cursor_right();
}
_ => {}
}
self.move_cursor_right();
}
pub fn delete_char(&mut self) {
let is_not_cursor_leftmost = match self.inputmode {
InputMode::PlaylistRename => self.pl_cursor_pos != 0,
InputMode::NewPlaylist => self.pl_new_pl_cursor_pos != 0,
InputMode::Editing => self.search_cursor_pos != 0,
_ => false,
};
@ -355,35 +320,27 @@ impl App {
let current_index = match self.inputmode {
InputMode::Editing => self.search_cursor_pos,
InputMode::PlaylistRename => self.pl_cursor_pos,
InputMode::NewPlaylist => self.pl_new_pl_cursor_pos,
_ => 0,
};
let from_left_to_current_index = current_index - 1;
if self.inputmode == InputMode::PlaylistRename {
// Getting all characters before the selected character.
let before_char_to_delete = self
.pl_newname_input
.chars()
.take(from_left_to_current_index);
// Getting all characters after selected character.
let after_char_to_delete = self.pl_newname_input.chars().skip(current_index);
// Put all characters together except the selected one.
// By leaving the selected one out, it is forgotten and therefore deleted.
self.pl_newname_input = before_char_to_delete.chain(after_char_to_delete).collect();
self.move_cursor_left();
} else if self.inputmode == InputMode::NewPlaylist {
let before_char_to_delete = self
.pl_new_pl_input
.chars()
.take(from_left_to_current_index);
let after_char_to_delete = self.pl_new_pl_input.chars().skip(current_index);
self.pl_new_pl_input = before_char_to_delete.chain(after_char_to_delete).collect();
self.move_cursor_left();
} else if self.inputmode == InputMode::Editing {
let before_char_to_delete =
self.search_input.chars().take(from_left_to_current_index);
let after_char_to_delete = self.search_input.chars().skip(current_index);
self.search_input = before_char_to_delete.chain(after_char_to_delete).collect();
self.move_cursor_left();
}
@ -393,7 +350,6 @@ impl App {
pub fn clamp_cursor(&self, new_cursor_pos: usize) -> usize {
match self.inputmode {
InputMode::PlaylistRename => new_cursor_pos.clamp(0, self.pl_newname_input.len()),
InputMode::NewPlaylist => new_cursor_pos.clamp(0, self.pl_new_pl_input.len()),
InputMode::Editing => new_cursor_pos.clamp(0, self.search_input.len()),
_ => 0,
}
@ -407,9 +363,6 @@ impl App {
InputMode::PlaylistRename => {
self.pl_cursor_pos = 0;
}
InputMode::NewPlaylist => {
self.pl_new_pl_cursor_pos = 0;
}
_ => {}
}
}
@ -427,36 +380,10 @@ impl App {
}
}
// Mouse event handlers
pub fn handle_scroll_up(&mut self) {
match self.selected_tab {
SelectedTab::Queue => {
self.queue_list.prev();
}
SelectedTab::DirectoryBrowser => {
self.browser.prev();
}
SelectedTab::Playlists => {
self.pl_list.prev();
}
pub fn change_playlist_name(&mut self) -> AppResult<()> {
if self.selected_tab == SelectedTab::Playlists {
self.inputmode = InputMode::PlaylistRename;
}
}
pub fn handle_scroll_down(&mut self) {
match self.selected_tab {
SelectedTab::Queue => {
self.queue_list.next();
}
SelectedTab::DirectoryBrowser => {
self.browser.next();
}
SelectedTab::Playlists => {
self.pl_list.next();
}
}
}
pub fn handle_mouse_left_click(&mut self, _x: u16, _y: u16) -> AppResult<()> {
Ok(())
}
}

View File

@ -32,7 +32,7 @@ impl FileBrowser {
let mut file_vec: Vec<(String, String)> = vec![];
let mut dir_vec: Vec<(String, String)> = vec![];
for (t, f) in conn.conn.listfiles(self.path.as_str())?.into_iter() {
if t == "directory" && !f.starts_with('.') {
if t == "directory" && !f.starts_with(".") {
dir_vec.push((t, f));
} else if t == "file"
&& Path::new(&f).has_extension(&[
@ -73,7 +73,7 @@ impl FileBrowser {
.lsinfo(Song {
file: (self.path.clone() + "/" + song)
.strip_prefix("./")
.unwrap_or("")
.unwrap_or_else(|| "")
.to_string(),
..Default::default()
})
@ -121,7 +121,7 @@ impl FileBrowser {
self.update_directory(conn)?;
}
} else {
self.path.clone_from(&self.prev_path);
self.path = self.prev_path.clone();
self.update_directory(conn)?;
}

View File

@ -5,13 +5,6 @@ use mpd::{Client, State};
use simple_dmenu::dmenu;
use std::time::Duration;
/// Defines the current status of volume (Muted or UnMuted)
#[derive(Debug)]
pub enum VolumeStatus {
Muted(i8),
Unmuted,
}
#[derive(Debug)]
/// struct storing the mpd Client related stuff
pub struct Connection {
@ -23,7 +16,6 @@ pub struct Connection {
pub current_song: Song,
pub stats: mpd::Stats,
pub status: mpd::Status,
pub volume_status: VolumeStatus,
}
impl Connection {
@ -49,9 +41,6 @@ impl Connection {
.currentsong()
.unwrap_or_else(|_| Some(empty_song.clone()))
.unwrap_or(empty_song);
let volume_status = VolumeStatus::Unmuted;
Ok(Self {
conn,
songs_filenames,
@ -61,7 +50,6 @@ impl Connection {
current_song,
stats,
status,
volume_status,
})
}
@ -169,10 +157,10 @@ impl Connection {
}
/// Given a song name from a directory, it returns the full path of the song in the database
pub fn get_full_path(&self, short_path: &str) -> Option<&str> {
pub fn get_full_path(&self, short_path: &str) -> Option<String> {
for (i, f) in self.songs_filenames.iter().enumerate() {
if f.contains(short_path) {
return Some(self.songs_filenames.get(i).unwrap());
return Some(self.songs_filenames.get(i).unwrap().to_string());
}
}
None
@ -219,7 +207,6 @@ impl Connection {
pub fn inc_volume(&mut self, v: i8) {
let cur = self.status.volume;
if cur + v <= 100 {
self.volume_status = VolumeStatus::Unmuted;
self.conn.volume(cur + v).unwrap();
}
}
@ -228,7 +215,6 @@ impl Connection {
pub fn dec_volume(&mut self, v: i8) {
let cur = self.status.volume;
if cur - v >= 0 {
self.volume_status = VolumeStatus::Unmuted;
self.conn.volume(cur - v).unwrap();
}
}

0
src/event_handler/event.rs → src/event/event.rs Normal file → Executable file
View File

44
src/event_handler/handler.rs → src/event/handler.rs Normal file → Executable file
View File

@ -1,12 +1,11 @@
use crate::{
app::{App, AppResult, SelectedTab},
connection::VolumeStatus,
ui::InputMode,
};
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers, MouseEvent, MouseEventKind};
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
use std::time::Duration;
use super::{new_pl_keys, pl_append_keys, pl_rename_keys, search_keys};
use super::{pl_append_keys, pl_rename_keys, search_keys};
pub fn handle_key_events(key_event: KeyEvent, app: &mut App) -> AppResult<()> {
// searching, playlist renaming, playlist appending
@ -14,8 +13,6 @@ pub fn handle_key_events(key_event: KeyEvent, app: &mut App) -> AppResult<()> {
search_keys::handle_search_keys(key_event, app)?;
} else if app.inputmode == InputMode::PlaylistRename {
pl_rename_keys::handle_pl_rename_keys(key_event, app)?;
} else if app.inputmode == InputMode::NewPlaylist {
new_pl_keys::handle_new_pl_keys(key_event, app)?;
} else if app.playlist_popup {
pl_append_keys::hande_pl_append_keys(key_event, app)?;
} else {
@ -141,22 +138,6 @@ pub fn handle_key_events(key_event: KeyEvent, app: &mut App) -> AppResult<()> {
app.conn.update_status();
}
// Toggle Mute
KeyCode::Char('m') => {
match app.conn.volume_status {
VolumeStatus::Muted(v) => {
app.conn.conn.volume(v)?;
app.conn.volume_status = VolumeStatus::Unmuted;
}
VolumeStatus::Unmuted => {
let current_volume = app.conn.status.volume;
app.conn.conn.volume(0)?;
app.conn.volume_status = VolumeStatus::Muted(current_volume);
}
}
app.conn.update_status();
}
// Update MPD database
KeyCode::Char('U') => {
app.conn.conn.rescan()?;
@ -297,10 +278,8 @@ pub fn handle_key_events(key_event: KeyEvent, app: &mut App) -> AppResult<()> {
// go to bottom of list
KeyCode::Char('G') => app.pl_list.index = app.pl_list.list.len() - 1,
// Playlist Rename
KeyCode::Char('R') => {
app.inputmode = InputMode::PlaylistRename;
}
// Change playlist name
KeyCode::Char('e') => app.change_playlist_name()?,
// add to current playlist
KeyCode::Enter | KeyCode::Char('l') | KeyCode::Right | KeyCode::Char(' ') => {
@ -318,18 +297,3 @@ pub fn handle_key_events(key_event: KeyEvent, app: &mut App) -> AppResult<()> {
}
Ok(())
}
pub fn handle_mouse_events(mouse_event: MouseEvent, app: &mut App) -> AppResult<()> {
match mouse_event.kind {
MouseEventKind::ScrollUp => app.handle_scroll_up(),
MouseEventKind::ScrollDown => app.handle_scroll_down(),
MouseEventKind::Down(button) => {
let (x, y) = (mouse_event.column, mouse_event.row);
if button == crossterm::event::MouseButton::Left {
app.handle_mouse_left_click(x, y)?;
}
}
_ => {}
}
Ok(())
}

1
src/event_handler/mod.rs → src/event/mod.rs Normal file → Executable file
View File

@ -3,4 +3,3 @@ pub mod handler;
pub mod search_keys;
pub mod pl_rename_keys;
pub mod pl_append_keys;
pub mod new_pl_keys;

View File

@ -1,5 +1,4 @@
use crate::app::{App, AppResult, SelectedTab};
use crate::ui::InputMode;
use crate::utils::FileExtension;
use crossterm::event::{KeyCode, KeyEvent};
use std::path::Path;
@ -29,14 +28,10 @@ pub fn hande_pl_append_keys(key_event: KeyEvent, app: &mut App) -> AppResult<()>
let option_song = songs.first();
if let Some(song) = option_song {
if *pl_name == "Current Playlist" {
app.conn.conn.push(song)?;
app.conn.conn.push(&song)?;
app.update_queue();
} else if *pl_name == "New Playlist" {
app.pl_new_pl_songs_buffer.clear();
app.pl_new_pl_songs_buffer.push(song.clone());
app.inputmode = InputMode::NewPlaylist;
} else {
app.conn.add_to_playlist(pl_name, song)?;
app.conn.add_to_playlist(pl_name, &song)?;
}
}
}
@ -47,23 +42,17 @@ pub fn hande_pl_append_keys(key_event: KeyEvent, app: &mut App) -> AppResult<()>
if t == "file" {
let short_path = f;
if let Some(full_path) = app.conn.get_full_path(short_path) {
let song = app.conn.get_song_with_only_filename(full_path);
let song = app.conn.get_song_with_only_filename(&full_path);
if *pl_name == "Current Playlist" {
app.conn.conn.push(&song)?;
app.update_queue();
} else if *pl_name == "New Playlist" {
app.pl_new_pl_songs_buffer.clear();
app.pl_new_pl_songs_buffer.push(song.clone());
app.inputmode = InputMode::NewPlaylist;
} else {
app.conn.add_to_playlist(pl_name, &song)?;
}
}
} else if t == "directory" {
let file = format!("{}/{}", app.browser.path, f);
app.pl_new_pl_songs_buffer.clear();
for (t, f) in app.conn.conn.listfiles(&file)?.iter() {
for (t, f) in app.conn.conn.listfiles(f)?.iter() {
// dir_vec.push((t, f));
if t == "file"
&& Path::new(&f).has_extension(&[
@ -72,12 +61,9 @@ pub fn hande_pl_append_keys(key_event: KeyEvent, app: &mut App) -> AppResult<()>
])
{
let full_path = app.conn.get_full_path(f).unwrap_or_default();
let song = app.conn.get_song_with_only_filename(full_path);
let song = app.conn.get_song_with_only_filename(&full_path);
if *pl_name == "Current Playlist" {
app.conn.conn.push(&song)?;
} else if *pl_name == "New Playlist" {
app.pl_new_pl_songs_buffer.push(song.clone());
app.inputmode = InputMode::NewPlaylist;
} else {
app.conn.add_to_playlist(pl_name, &song)?;
}
@ -91,14 +77,14 @@ pub fn hande_pl_append_keys(key_event: KeyEvent, app: &mut App) -> AppResult<()>
if *pl_name == "Current Playlist" {
app.conn.load_playlist(playlist_name)?;
app.update_queue();
} else if *pl_name == "New Playlist" {
app.inputmode = InputMode::NewPlaylist;
} else {
let songs = app.conn.conn.playlist(playlist_name)?;
for song in songs {
// We ignore the Err() since there could be songs in playlists, which do not exist in the db anymore.
// So instead of panicking, we just ignore if the song does not exists
app.conn.add_to_playlist(pl_name, &song).unwrap_or(());
app.conn
.add_to_playlist(*pl_name, &song)
.unwrap_or_else(|_| {});
}
}
}

View File

View File

View File

@ -1,47 +0,0 @@
use crate::{
app::{App, AppResult},
ui::InputMode,
};
use crossterm::event::{KeyCode, KeyEvent};
pub fn handle_new_pl_keys(key_event: KeyEvent, app: &mut App) -> AppResult<()> {
match key_event.code {
KeyCode::Esc => {
app.pl_new_pl_input.clear();
app.reset_cursor();
app.inputmode = InputMode::Normal;
}
KeyCode::Char(to_insert) => {
app.enter_char(to_insert);
}
KeyCode::Enter => {
let pl_name = &app.pl_new_pl_input;
for song in app.pl_new_pl_songs_buffer.iter() {
app.conn.conn.pl_push(pl_name, song)?;
}
app.pl_new_pl_input.clear();
app.pl_list.list = App::get_playlist(&mut app.conn.conn)?;
app.append_list = App::get_append_list(&mut app.conn.conn)?;
app.reset_cursor();
app.inputmode = InputMode::Normal;
}
KeyCode::Backspace => {
app.delete_char();
}
KeyCode::Left => {
app.move_cursor_left();
}
KeyCode::Right => {
app.move_cursor_right();
}
_ => {}
}
Ok(())
}

View File

@ -14,7 +14,7 @@ pub mod list;
pub mod browser;
/// Event Handler/ keymaps
pub mod event_handler;
pub mod event;
/// Application
pub mod app;

View File

@ -1,9 +1,9 @@
use ratatui::prelude::*;
use rmptui::app::App;
use rmptui::app::AppResult;
use rmptui::event_handler::event::Event;
use rmptui::event_handler::event::EventHandler;
use rmptui::event_handler::handler;
use rmptui::event::event::Event;
use rmptui::event::event::EventHandler;
use rmptui::event::handler;
use rmptui::tui;
use std::env;
use std::io;
@ -35,7 +35,7 @@ fn main() -> AppResult<()> {
match tui.events.next()? {
Event::Tick => app.tick()?,
Event::Key(key_event) => handler::handle_key_events(key_event, &mut app)?,
Event::Mouse(mouse_event) => handler::handle_mouse_events(mouse_event, &mut app)?,
Event::Mouse(_) => {}
Event::Resize(_, _) => {}
}
}

View File

@ -5,7 +5,7 @@ use crossterm::terminal::{self, *};
use std::panic;
use crate::app::{App, AppResult};
use crate::event_handler::event::EventHandler;
use crate::event::event::EventHandler;
pub type CrosstermTerminal = ratatui::Terminal<ratatui::backend::CrosstermBackend<std::io::Stderr>>;

View File

@ -1,9 +1,6 @@
use std::time::Duration;
use crate::{
app::{App, SelectedTab},
connection::VolumeStatus,
};
use crate::app::{App, SelectedTab};
use ratatui::{
prelude::*,
widgets::{block::Title, *},
@ -14,7 +11,6 @@ pub enum InputMode {
Editing,
Normal,
PlaylistRename,
NewPlaylist,
}
/// Renders the user interface widgets
@ -41,9 +37,6 @@ pub fn render(app: &mut App, frame: &mut Frame) {
InputMode::PlaylistRename => {
draw_rename_playlist(frame, app, layout[1]);
}
InputMode::NewPlaylist => {
draw_new_playlist(frame, app, layout[1]);
}
}
if app.playlist_popup {
@ -83,7 +76,7 @@ fn draw_directory_browser(frame: &mut Frame, app: &mut App, size: Rect) {
let mut status: bool = false;
for sn in app.queue_list.list.iter() {
let file = sn.file.split('/').last().unwrap_or_default();
let file = sn.file.split("/").last().unwrap_or_default();
if file.eq(s) {
status = true;
}
@ -108,6 +101,7 @@ fn draw_directory_browser(frame: &mut Frame, app: &mut App, size: Rect) {
}
});
let mut state = TableState::new();
let header = ["Artist", "Track", "Title", "Album", "Time"]
.into_iter()
.map(Cell::from)
@ -131,15 +125,10 @@ fn draw_directory_browser(frame: &mut Frame, app: &mut App, size: Rect) {
Title::from(format!("Total Songs: {}", total_songs).green())
.alignment(Alignment::Center),
)
.title(match app.conn.volume_status {
VolumeStatus::Unmuted => {
Title::from(format!("Volume: {}%", app.conn.status.volume).green())
.alignment(Alignment::Right)
}
VolumeStatus::Muted(_v) => {
Title::from("Muted".red()).alignment(Alignment::Right)
}
})
.title(
Title::from(format!("Volume: {}%", app.conn.status.volume).green())
.alignment(Alignment::Right),
)
.borders(Borders::ALL),
)
.highlight_style(
@ -151,8 +140,8 @@ fn draw_directory_browser(frame: &mut Frame, app: &mut App, size: Rect) {
.header(header)
.flex(layout::Flex::Legacy);
app.browser_state.select(Some(app.browser.selected));
frame.render_stateful_widget(table, size, &mut app.browser_state);
state.select(Some(app.browser.selected));
frame.render_stateful_widget(table, size, &mut state);
}
/// draws playing queue
@ -207,6 +196,7 @@ fn draw_queue(frame: &mut Frame, app: &mut App, size: Rect) {
}
});
let mut state = TableState::new();
let header = ["Artist", "Track", "Title", "Album", "Time"]
.into_iter()
.map(Cell::from)
@ -229,15 +219,10 @@ fn draw_queue(frame: &mut Frame, app: &mut App, size: Rect) {
.title(Title::from(
format!("({} items)", app.queue_list.list.len()).bold(),
))
.title(match app.conn.volume_status {
VolumeStatus::Unmuted => {
Title::from(format!("Volume: {}%", app.conn.status.volume).green())
.alignment(Alignment::Right)
}
VolumeStatus::Muted(_v) => {
Title::from("Muted".red()).alignment(Alignment::Right)
}
})
.title(
Title::from(format!("Volume: {}%", app.conn.status.volume).green())
.alignment(Alignment::Right),
)
.borders(Borders::ALL),
)
.highlight_style(
@ -249,8 +234,8 @@ fn draw_queue(frame: &mut Frame, app: &mut App, size: Rect) {
.header(header)
.flex(layout::Flex::Legacy);
app.queue_state.select(Some(app.queue_list.index));
frame.render_stateful_widget(table, size, &mut app.queue_state);
state.select(Some(app.queue_list.index));
frame.render_stateful_widget(table, size, &mut state);
}
// Draw search bar
@ -288,7 +273,7 @@ fn draw_progress_bar(frame: &mut Frame, app: &mut App, size: Rect) {
// Get the current playing state
let mut state: String = String::new();
if !app.queue_list.list.is_empty() {
state.clone_from(&app.conn.state);
state = app.conn.state.clone();
state.push(':');
}
@ -351,6 +336,7 @@ fn draw_playlist_viewer(frame: &mut Frame, app: &mut App, area: Rect) {
.split(area);
// Draw list of playlists
let mut state = ListState::default();
let title = Block::default().title(Title::from("Playlist".green().bold()));
let list = List::new(app.pl_list.list.clone())
.block(title.borders(Borders::ALL))
@ -362,8 +348,8 @@ fn draw_playlist_viewer(frame: &mut Frame, app: &mut App, area: Rect) {
.add_modifier(Modifier::REVERSED),
)
.repeat_highlight_symbol(true);
app.playlists_state.select(Some(app.pl_list.index));
frame.render_stateful_widget(list, layouts[0], &mut app.playlists_state);
state.select(Some(app.pl_list.index));
frame.render_stateful_widget(list, layouts[0], &mut state);
// Playlist viewer
@ -457,26 +443,6 @@ fn draw_rename_playlist(frame: &mut Frame, app: &mut App, area: Rect) {
frame.render_widget(input, area);
}
fn draw_new_playlist(frame: &mut Frame, app: &mut App, area: Rect) {
#[allow(clippy::cast_possible_truncation)]
frame.set_cursor(
// Draw the cursor at the current position in the input field.
// This position is can be controlled via the left and right arrow key
area.x + app.pl_new_pl_cursor_pos as u16 + 2,
// Move one line down, from the border to the input line
area.y + 1,
);
let input = Paragraph::new("/".to_string() + &app.pl_new_pl_input)
.style(Style::default())
.block(
Block::default()
.borders(Borders::ALL)
.title("Enter New Playlist's Name: ".bold().green()),
);
frame.render_widget(input, area);
}
fn centered_rect(percent_x: u16, percent_y: u16, r: Rect) -> Rect {
let popup_layout = Layout::vertical([
Constraint::Percentage((100 - percent_y) / 2),