aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xREADME.md2
-rwxr-xr-xsrc/app.rs55
-rwxr-xr-xsrc/event/handler.rs10
-rwxr-xr-xsrc/event/mod.rs1
-rw-r--r--src/event/new_pl_keys.rs45
-rwxr-xr-xsrc/event/pl_append_keys.rs15
-rwxr-xr-xsrc/ui.rs24
-rw-r--r--todo.md2
8 files changed, 136 insertions, 18 deletions
diff --git a/README.md b/README.md
index d886d91..fe69453 100755
--- a/README.md
+++ b/README.md
@@ -38,6 +38,7 @@ 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 |
@@ -54,4 +55,5 @@ 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
diff --git a/src/app.rs b/src/app.rs
index 9b2d2fd..4b7b73e 100755
--- a/src/app.rs
+++ b/src/app.rs
@@ -25,9 +25,14 @@ 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,
@@ -80,6 +85,9 @@ 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,
@@ -136,6 +144,7 @@ impl App {
pub fn get_append_list(conn: &mut Client) -> AppResult<ContentList<String>> {
let mut list = ContentList::new();
+ list.list.push("New Playlist".to_string());
list.list.push("Current Playlist".to_string());
for item in Self::get_playlist(conn)? {
list.list.push(item.to_string());
@@ -286,6 +295,10 @@ 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);
+ }
_ => {}
}
}
@@ -300,6 +313,12 @@ 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);
+ }
+
_ => {}
}
}
@@ -308,19 +327,24 @@ impl App {
match self.inputmode {
InputMode::PlaylistRename => {
self.pl_newname_input.insert(self.pl_cursor_pos, new_char);
- self.move_cursor_right();
+ }
+ InputMode::NewPlaylist => {
+ self.pl_new_pl_input
+ .insert(self.pl_new_pl_cursor_pos, new_char);
}
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,
};
@@ -333,27 +357,35 @@ 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();
}
@@ -363,6 +395,7 @@ 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,
}
@@ -376,6 +409,9 @@ impl App {
InputMode::PlaylistRename => {
self.pl_cursor_pos = 0;
}
+ InputMode::NewPlaylist => {
+ self.pl_new_pl_cursor_pos = 0;
+ }
_ => {}
}
}
@@ -393,13 +429,6 @@ impl App {
}
}
- pub fn change_playlist_name(&mut self) -> AppResult<()> {
- if self.selected_tab == SelectedTab::Playlists {
- self.inputmode = InputMode::PlaylistRename;
- }
- Ok(())
- }
-
// Mouse event handlers
pub fn handle_scroll_up(&mut self) {
match self.selected_tab {
diff --git a/src/event/handler.rs b/src/event/handler.rs
index 02bdb14..8fd4286 100755
--- a/src/event/handler.rs
+++ b/src/event/handler.rs
@@ -6,7 +6,7 @@ use crate::{
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers, MouseEvent, MouseEventKind};
use std::time::Duration;
-use super::{pl_append_keys, pl_rename_keys, search_keys};
+use super::{pl_append_keys, pl_rename_keys, new_pl_keys, search_keys};
pub fn handle_key_events(key_event: KeyEvent, app: &mut App) -> AppResult<()> {
// searching, playlist renaming, playlist appending
@@ -14,6 +14,8 @@ 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 {
@@ -295,8 +297,10 @@ 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,
- // Change playlist name
- KeyCode::Char('e') => app.change_playlist_name()?,
+ // Playlist Rename
+ KeyCode::Char('R') => {
+ app.inputmode = InputMode::PlaylistRename;
+ }
// add to current playlist
KeyCode::Enter | KeyCode::Char('l') | KeyCode::Right | KeyCode::Char(' ') => {
diff --git a/src/event/mod.rs b/src/event/mod.rs
index e0f3b13..efc9b9e 100755
--- a/src/event/mod.rs
+++ b/src/event/mod.rs
@@ -3,3 +3,4 @@ pub mod handler;
pub mod search_keys;
pub mod pl_rename_keys;
pub mod pl_append_keys;
+pub mod new_pl_keys;
diff --git a/src/event/new_pl_keys.rs b/src/event/new_pl_keys.rs
new file mode 100644
index 0000000..75c9e97
--- /dev/null
+++ b/src/event/new_pl_keys.rs
@@ -0,0 +1,45 @@
+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.reset_cursor();
+ app.inputmode = InputMode::Normal;
+ }
+
+ KeyCode::Backspace => {
+ app.delete_char();
+ }
+
+ KeyCode::Left => {
+ app.move_cursor_left();
+ }
+
+ KeyCode::Right => {
+ app.move_cursor_right();
+ }
+
+ _ => {}
+ }
+ Ok(())
+}
diff --git a/src/event/pl_append_keys.rs b/src/event/pl_append_keys.rs
index f56d597..0f7df81 100755
--- a/src/event/pl_append_keys.rs
+++ b/src/event/pl_append_keys.rs
@@ -1,4 +1,5 @@
use crate::app::{App, AppResult, SelectedTab};
+use crate::ui::InputMode;
use crate::utils::FileExtension;
use crossterm::event::{KeyCode, KeyEvent};
use std::path::Path;
@@ -30,6 +31,10 @@ pub fn hande_pl_append_keys(key_event: KeyEvent, app: &mut App) -> AppResult<()>
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)?;
}
@@ -47,12 +52,17 @@ pub fn hande_pl_append_keys(key_event: KeyEvent, app: &mut App) -> AppResult<()>
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() {
// dir_vec.push((t, f));
if t == "file"
@@ -65,6 +75,9 @@ pub fn hande_pl_append_keys(key_event: KeyEvent, app: &mut App) -> AppResult<()>
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)?;
}
@@ -78,6 +91,8 @@ 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 {
diff --git a/src/ui.rs b/src/ui.rs
index adf9d43..bd21e08 100755
--- a/src/ui.rs
+++ b/src/ui.rs
@@ -14,6 +14,7 @@ pub enum InputMode {
Editing,
Normal,
PlaylistRename,
+ NewPlaylist,
}
/// Renders the user interface widgets
@@ -40,6 +41,9 @@ 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 {
@@ -453,6 +457,26 @@ 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),
diff --git a/todo.md b/todo.md
deleted file mode 100644
index 390c3a2..0000000
--- a/todo.md
+++ /dev/null
@@ -1,2 +0,0 @@
-- [ ] create new playlist
-- [ ] add to new playlist