This commit is contained in:
krolxon 2024-04-23 19:16:42 +05:30
parent a0582ead78
commit 05c4b17bc0
6 changed files with 146 additions and 33 deletions

View File

@ -1,5 +1,6 @@
use crate::connection::Connection;
use crate::connection::{self, Connection};
use crate::list::ContentList;
use mpd::Client;
use std::collections::VecDeque;
// Application result type
@ -12,20 +13,30 @@ pub struct App {
pub running: bool,
pub conn: Connection,
pub play_deque: VecDeque<String>,
pub list: ContentList,
pub song_list: ContentList<String>,
pub queue_list: ContentList<String>,
pub pl_list: ContentList<String>,
}
impl App {
pub fn new(addrs: &str) -> Self {
pub fn builder(addrs: &str) -> AppResult<Self> {
let mut conn = Connection::new(addrs).unwrap();
let mut vec: VecDeque<String> = VecDeque::new();
let mut pl_list = ContentList::new();
pl_list.list = Self::get_playlist(&mut conn.conn)?;
Self::get_queue(&mut conn, &mut vec);
Self {
let mut song_list = ContentList::new();
song_list.list = conn.songs_filenames.clone();
Ok(Self {
running: true,
conn,
play_deque: vec,
list: ContentList::new(),
}
song_list,
queue_list: ContentList::new(),
pl_list,
})
}
pub fn tick(&self) {}
@ -52,10 +63,15 @@ impl App {
self.play_deque.clear();
Self::get_queue(&mut self.conn, &mut self.play_deque);
}
}
fn to_vecdeque(filenames: &Vec<String>) -> VecDeque<String> {
let mut v: VecDeque<String> = VecDeque::new();
v = filenames.iter().map(|x| x.to_string()).collect();
v
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)
}
pub fn update_playlist(&mut self) -> AppResult<()> {
Self::get_playlist(&mut self.conn.conn)?;
Ok(())
}
}

View File

@ -10,6 +10,7 @@ pub type Error = Box<dyn std::error::Error>;
pub struct Connection {
pub conn: Client,
pub songs_filenames: Vec<String>,
// pub state: String,
}
impl Connection {
@ -25,6 +26,7 @@ impl Connection {
Ok(Self {
conn,
songs_filenames,
// state: "Stopped".to_string(),
})
}
@ -50,14 +52,22 @@ impl Connection {
Ok(())
}
// pub fn update_state(&mut self) {
// match self.conn.status().unwrap().state {
// State::Stop => self.state = "Stopped".to_string(),
// State::Play => self.state = "Playing".to_string(),
// State::Pause => self.state = "Paused".to_string(),
// }
// }
pub fn push(&mut self, song: &Song) -> Result<()> {
if self.conn.queue().unwrap().is_empty() {
self.conn.push(song).unwrap();
self.conn.play().unwrap();
} else {
self.conn.push(song).unwrap();
if self.conn.status().unwrap().state == State::Stop {
self.conn.play().unwrap();
self.conn.push(song)?;
if self.conn.status()?.state == State::Stop {
self.conn.play()?;
}
self.conn.next().unwrap();
}
@ -65,6 +75,19 @@ impl Connection {
Ok(())
}
pub fn push_playlist(&mut self, playlist: &str) -> Result<()> {
let songs: Vec<Song> = self.conn.playlist(playlist)?;
for song in songs {
if self.songs_filenames.contains(&song.file) {
let song = self.get_song_with_only_filename(&song.file);
self.conn.push(&song)?;
self.conn.play()?;
}
}
Ok(())
}
pub fn get_song_with_only_filename(&self, filename: &str) -> Song {
Song {
file: filename.to_string(),
@ -81,7 +104,6 @@ impl Connection {
pub fn get_current_song(&mut self) -> Option<String> {
self.conn.currentsong().unwrap().unwrap_or_default().title
}
pub fn status(&mut self) {
let current_song = self.conn.currentsong();
@ -99,6 +121,19 @@ impl Connection {
);
}
pub fn now_playing(&mut self) -> Option<String> {
let song = self.conn.currentsong().unwrap().unwrap_or_default();
if let Some(s) = song.title {
if let Some(a) = song.artist {
Some(format!("{} - {}", s, a))
} else {
Some(s)
}
} else {
None
}
}
// Playback controls
pub fn pause(&mut self) {
self.conn.pause(true).unwrap();

View File

@ -11,17 +11,17 @@ pub fn handle_key_events(key_event: KeyEvent, app: &mut App) -> AppResult<()> {
}
KeyCode::Char('j') => {
app.list.next();
app.song_list.next();
}
KeyCode::Char('k') => {
app.list.prev();
app.song_list.prev();
}
KeyCode::Enter | KeyCode::Char('l') => {
let song = app.conn.get_song_with_only_filename(app.conn.songs_filenames.get(app.list.index).unwrap());
app.conn.push(&song).unwrap();
app.update_queue();
let song = app.conn.get_song_with_only_filename(app.conn.songs_filenames.get(app.song_list.index).unwrap());
app.conn.push(&song)?;
// app.update_queue();
}
// Playback controls
@ -35,10 +35,42 @@ pub fn handle_key_events(key_event: KeyEvent, app: &mut App) -> AppResult<()> {
app.conn.pause();
}
// Clearn Queue
KeyCode::Char('x') => {
app.conn.conn.clear()?;
app.update_queue();
// app.update_queue();
}
KeyCode::Char('d') => {
app.conn.play_dmenu()?;
}
KeyCode::Down=> {
app.pl_list.next();
}
KeyCode::Up=> {
app.pl_list.prev();
}
KeyCode::Right => {
app.conn.push_playlist(app.pl_list.list.get(app.pl_list.index).unwrap())?;
}
KeyCode::Char('f')=> {
// let place = app.conn.conn.status().unwrap().duration;
let (pos, _) = app.conn.conn.status().unwrap().time.unwrap();
let pos: i64 = (pos.as_secs() + 2).try_into().unwrap();
app.conn.conn.seek(2, pos )?;
}
KeyCode::Char('b')=> {
// let place = app.conn.conn.status().unwrap().duration;
let (pos, _) = app.conn.conn.status().unwrap().time.unwrap();
let pos: i64 = (pos.as_secs() - 2).try_into().unwrap();
app.conn.conn.seek(2, pos )?;
}
_ => {}
}

View File

@ -1,11 +1,13 @@
#[derive(Debug)]
pub struct ContentList {
pub struct ContentList<T> {
pub list: Vec<T>,
pub index: usize
}
impl ContentList {
impl<T> ContentList<T> {
pub fn new() -> Self {
ContentList {
list: Vec::new(),
index: 0
}
}

View File

@ -42,7 +42,7 @@ fn main() -> AppResult<()> {
let backend = CrosstermBackend::new(io::stderr());
let terminal = Terminal::new(backend)?;
let mut app = App::new("127.0.0.1:6600");
let mut app = App::builder("127.0.0.1:6600")?;
let events = EventHandler::new(250);
let mut tui = tui::Tui::new(terminal, events);

View File

@ -1,4 +1,4 @@
use crate::{app::App, connection::Connection};
use crate::app::App;
use ratatui::{prelude::*, widgets::*};
/// Renders the user interface widgets
@ -9,7 +9,7 @@ pub fn render(app: &mut App, frame: &mut Frame) {
// - https://github.com/ratatui-org/ratatui/tree/master/examples
// List of songs
let mut state = ListState::default();
let mut song_state = ListState::default();
let size = Rect::new(100, 0, frame.size().width, frame.size().height - 3);
let list = List::new(app.conn.songs_filenames.clone())
.block(Block::default().title("Song List").borders(Borders::ALL))
@ -17,21 +17,49 @@ pub fn render(app: &mut App, frame: &mut Frame) {
.highlight_symbol(">>")
.repeat_highlight_symbol(true);
state.select(Some(app.list.index));
frame.render_stateful_widget(list, size, &mut state);
song_state.select(Some(app.song_list.index));
frame.render_stateful_widget(list, size, &mut song_state);
// Play Queue
let mut queue_state = ListState::default();
let size = Rect::new(0, 0, 100, frame.size().height - 25);
let list = List::new(app.play_deque.clone())
.block(Block::default().title("Play Queue").borders(Borders::ALL))
.highlight_style(Style::new().add_modifier(Modifier::REVERSED))
.highlight_symbol(">>")
.repeat_highlight_symbol(true);
frame.render_widget(list, size);
app.update_queue();
frame.render_stateful_widget(list, size, &mut queue_state);
// Status
let size = Rect::new(0, frame.size().height - 3, frame.size().width, 3);
let status = Paragraph::new(app.conn.conn.status().unwrap().volume.to_string())
.block(Block::default().title("Status").borders(Borders::ALL));
frame.render_widget(status, size);
// let size = Rect::new(0, frame.size().height - 3, frame.size().width, 3);
// let song = app
// .conn
// .now_playing()
// .unwrap_or_else(|| "No Title Found".to_string());
//
// let (elapsed, total) = app.conn.conn.status().unwrap().time.unwrap();
//
// let mut lines = vec![];
// lines.push(Line::from(vec![
// Span::styled("Current: ", Style::default().fg(Color::Red)),
// Span::styled(song, Style::default().fg(Color::Yellow)),
// Span::styled(format!("[{}/{}]", elapsed.as_secs(), total.as_secs()), Style::default().fg(Color::Yellow)),
// ]));
// let status = Paragraph::new(Text::from(lines))
// .block(Block::default().title("Status").borders(Borders::ALL));
// frame.render_widget(status, size);
// Playlists
let mut state = ListState::default();
let size = Rect::new(0, 25, 100, frame.size().height - 25 - 3);
let list = List::new(app.pl_list.list.clone())
.block(Block::default().title("Playlists").borders(Borders::ALL))
.highlight_style(Style::new().add_modifier(Modifier::REVERSED))
.highlight_symbol(">>")
.repeat_highlight_symbol(true);
state.select(Some(app.pl_list.index));
frame.render_stateful_widget(list, size, &mut state);
}