Krolyxon
Commit 00c5c12

rmptui00c5c12

use filetree view instead of all song list

Author
krolxon
Date
2024-04-25 14:31 +0530
Parent
f665c4e
Commit
00c5c12d82a2d6b9ca5f56f6ca468b2b3212c792

+158 −17

5 files changed

  1. M src/app.rs +12 −7
  2. A src/browser.rs +92 −0
  3. M src/handler.rs +15 −8
  4. M src/lib.rs +3 −0
  5. M src/ui.rs +36 −2
M src/app.rs View
@@ -1,5 +1,6 @@
11 use std::time::Duration;
22
3+use crate::browser::FileBrowser;
34 use crate::connection::Connection;
45 use crate::list::ContentList;
56 use mpd::Client;
@@ -17,11 +18,12 @@ pub struct App {
1718 pub queue_list: ContentList<String>,
1819 pub pl_list: ContentList<String>,
1920 pub selected_tab: SelectedTab,
21+ pub browser: FileBrowser,
2022 }
2123
2224 #[derive(Debug, PartialEq, Clone)]
2325 pub enum SelectedTab {
24− SongList,
26+ DirectoryBrowser,
2527 Queue,
2628 Playlists,
2729 }
@@ -29,9 +31,9 @@ pub enum SelectedTab {
2931 impl SelectedTab {
3032 fn as_usize(&self) {
3133 match self {
32− SelectedTab::SongList => 0,
33− SelectedTab::Queue => 1,
34− SelectedTab::Playlists => 2,
34+ SelectedTab::Queue => 0,
35+ SelectedTab::Playlists => 1,
36+ SelectedTab::DirectoryBrowser => 2,
3537 };
3638 }
3739 }
@@ -48,13 +50,15 @@ impl App {
4850 let mut song_list = ContentList::new();
4951 song_list.list = conn.songs_filenames.clone();
5052
53+ let browser = FileBrowser::new();
5154 Ok(Self {
5255 running: true,
5356 conn,
5457 song_list,
5558 queue_list,
5659 pl_list,
57− selected_tab: SelectedTab::SongList,
60+ selected_tab: SelectedTab::DirectoryBrowser,
61+ browser,
5862 })
5963 }
6064
@@ -62,6 +66,7 @@ impl App {
6266 self.conn.update_state();
6367 self.conn.update_progress();
6468 self.update_queue();
69+ self.browser.update_directory(&mut self.conn).unwrap();
6570 }
6671
6772 pub fn quit(&mut self) {
@@ -103,9 +108,9 @@ impl App {
103108
104109 pub fn cycle_tabls(&mut self) {
105110 self.selected_tab = match self.selected_tab {
106− SelectedTab::SongList => SelectedTab::Queue,
111+ SelectedTab::DirectoryBrowser => SelectedTab::Queue,
107112 SelectedTab::Queue => SelectedTab::Playlists,
108− SelectedTab::Playlists => SelectedTab::SongList,
113+ SelectedTab::Playlists => SelectedTab::DirectoryBrowser,
109114 };
110115 }
111116 }
A src/browser.rs View
@@ -0,0 +1,92 @@
1+use mpd::Query;
2+
3+use crate::{app::AppResult, connection::Connection};
4+
5+#[derive(Debug)]
6+pub struct FileBrowser {
7+ pub filetree: Vec<(String, String)>,
8+ pub selected: usize,
9+ pub prev_selected: usize,
10+ pub path: String,
11+ pub prev_path: String,
12+}
13+
14+impl FileBrowser {
15+ pub fn new() -> FileBrowser {
16+ FileBrowser {
17+ filetree: Vec::new(),
18+ selected: 0,
19+ prev_selected: 0,
20+ path: ".".to_string(),
21+ prev_path: ".".to_string(),
22+ }
23+ }
24+
25+ pub fn update_directory(&mut self, conn: &mut Connection) -> AppResult<()> {
26+ self.filetree.clear();
27+ self.filetree = conn
28+ .conn
29+ .listfiles(self.path.as_str())?
30+ .into_iter()
31+ .filter(|(f, _)| f == "directory" || f == "file")
32+ .collect::<Vec<(String, String)>>();
33+
34+ Ok(())
35+ }
36+
37+ // Go to next item in filetree
38+ pub fn next(&mut self) {
39+ // if self.selected < self.filetree.len() - 1 {
40+ // self.selected += 1;
41+ // }
42+
43+ if self.selected == self.filetree.len() - 1 {
44+ self.selected = 0;
45+ } else {
46+ self.selected += 1;
47+ }
48+ }
49+
50+ /// Go to previous item in filetree
51+ pub fn prev(&mut self) {
52+ if self.selected == 0 {
53+ self.selected = self.filetree.len() - 1;
54+ } else {
55+ self.selected -= 1;
56+ }
57+ }
58+
59+ pub fn handle_enter(&mut self, conn: &mut Connection) -> AppResult<()> {
60+ let (t, path) = self.filetree.get(self.selected).unwrap();
61+ if t == "directory" {
62+ if path != "." {
63+ self.prev_path = self.path.clone();
64+ self.path = path.to_string();
65+ self.update_directory(conn)?;
66+ self.prev_selected = self.selected;
67+ self.selected = 0;
68+ }
69+ } else {
70+ let list = conn
71+ .songs_filenames
72+ .iter()
73+ .map(|f| f.as_str())
74+ .collect::<Vec<&str>>();
75+ let (filename, _) = rust_fuzzy_search::fuzzy_search_sorted(&path, &list)
76+ .get(0)
77+ .unwrap()
78+ .clone();
79+
80+ let song = conn.get_song_with_only_filename(filename);
81+ conn.push(&song)?;
82+ }
83+ Ok(())
84+ }
85+
86+ pub fn handle_go_back(&mut self, conn: &mut Connection) -> AppResult<()> {
87+ self.path = self.prev_path.clone();
88+ self.selected = self.prev_selected;
89+ self.update_directory(conn)?;
90+ Ok(())
91+ }
92+}
M src/handler.rs View
@@ -17,13 +17,13 @@ pub fn handle_key_events(key_event: KeyEvent, app: &mut App) -> AppResult<()> {
1717 }
1818
1919 KeyCode::Char('j') | KeyCode::Down => match app.selected_tab {
20− SelectedTab::SongList => app.song_list.next(),
20+ SelectedTab::DirectoryBrowser => app.browser.next(),
2121 SelectedTab::Queue => app.queue_list.next(),
2222 SelectedTab::Playlists => app.pl_list.next(),
2323 },
2424
2525 KeyCode::Char('k') | KeyCode::Up => match app.selected_tab {
26− SelectedTab::SongList => app.song_list.prev(),
26+ SelectedTab::DirectoryBrowser => app.browser.prev(),
2727 SelectedTab::Queue => app.queue_list.prev(),
2828 SelectedTab::Playlists => app.pl_list.prev(),
2929 },
@@ -32,12 +32,10 @@ pub fn handle_key_events(key_event: KeyEvent, app: &mut App) -> AppResult<()> {
3232 // app.update_queue();
3333
3434 match app.selected_tab {
35− SelectedTab::SongList => {
36− let song = app.conn.get_song_with_only_filename(
37− app.conn.songs_filenames.get(app.song_list.index).unwrap(),
38− );
39− app.conn.push(&song)?;
35+ SelectedTab::DirectoryBrowser => {
36+ app.browser.handle_enter(&mut app.conn)?;
4037 }
38+
4139 SelectedTab::Queue => {
4240 let song = app.conn.get_song_with_only_filename(
4341 app.queue_list.list.get(app.queue_list.index).unwrap(),
@@ -51,6 +49,14 @@ pub fn handle_key_events(key_event: KeyEvent, app: &mut App) -> AppResult<()> {
5149 }
5250 }
5351
52+ KeyCode::Char('h') => match app.selected_tab {
53+ SelectedTab::DirectoryBrowser => {
54+ app.browser.handle_go_back(&mut app.conn)?;
55+ }
56+ SelectedTab::Queue => {}
57+ SelectedTab::Playlists => {}
58+ },
59+
5460 // Playback controls
5561 // Toggle Pause
5662 KeyCode::Char('p') => {
@@ -105,7 +111,7 @@ pub fn handle_key_events(key_event: KeyEvent, app: &mut App) -> AppResult<()> {
105111 }
106112
107113 KeyCode::Char('1') => {
108− app.selected_tab = SelectedTab::SongList;
114+ app.selected_tab = SelectedTab::DirectoryBrowser;
109115 }
110116
111117 KeyCode::Char('2') => {
@@ -116,6 +122,7 @@ pub fn handle_key_events(key_event: KeyEvent, app: &mut App) -> AppResult<()> {
116122 app.selected_tab = SelectedTab::Playlists;
117123 }
118124
125+
119126 KeyCode::Char('n') => {
120127 app.conn.conn.next()?;
121128 }
M src/lib.rs View
@@ -13,6 +13,9 @@ pub mod tui;
1313 /// Content list
1414 pub mod list;
1515
16+/// File Browser
17+pub mod browser;
18+
1619 /// Event Handler
1720 pub mod event;
1821
M src/ui.rs View
@@ -1,4 +1,7 @@
1−use crate::app::{App, AppResult, SelectedTab};
1+use crate::{
2+ app::{App, AppResult, SelectedTab},
3+ browser::FileBrowser,
4+};
25 use ratatui::{
36 prelude::*,
47 widgets::{block::Title, *},
@@ -48,9 +51,10 @@ pub fn render(app: &mut App, frame: &mut Frame) {
4851 // frame.render_widget(tab, layout[0]);
4952
5053 match app.selected_tab {
51− SelectedTab::SongList => draw_song_list(frame, app, layout[1]),
54+ // SelectedTab::SongList => draw_song_list(frame, app, layout[1]),
5255 SelectedTab::Queue => draw_queue(frame, app, layout[1]),
5356 SelectedTab::Playlists => draw_playlists(frame, app, layout[1]),
57+ SelectedTab::DirectoryBrowser => draw_directory_browser(frame, app, layout[1]),
5458 }
5559 }
5660
@@ -147,3 +151,33 @@ fn draw_progress_bar(frame: &mut Frame, app: &mut App, size: Rect) {
147151
148152 frame.render_widget(progress_bar, size);
149153 }
154+
155+fn draw_directory_browser(frame: &mut Frame, app: &mut App, size: Rect) {
156+ let mut song_state = ListState::default();
157+ let total_songs = app.conn.conn.stats().unwrap().songs.to_string();
158+ let mut list: Vec<String> = vec![];
159+ for (t, s) in app.browser.filetree.iter() {
160+ if t == "file" {
161+ list.push(s.to_string());
162+ } else {
163+ list.push(format!("[{}]", *s));
164+ }
165+ }
166+ let list = List::new(list)
167+ .block(
168+ Block::default()
169+ .title(format!("File Browser: {}", app.browser.path.clone()).bold())
170+ .title(
171+ Title::from(format!("Total Songs: {}", total_songs).bold().green())
172+ .alignment(Alignment::Right),
173+ )
174+ .borders(Borders::ALL),
175+ )
176+ .highlight_style(Style::new().add_modifier(Modifier::REVERSED))
177+ .highlight_symbol(">>")
178+ .repeat_highlight_symbol(true)
179+ .scroll_padding(20);
180+
181+ song_state.select(Some(app.browser.selected));
182+ frame.render_stateful_widget(list, size, &mut song_state);
183+}