Krolyxon
Commit 04e5d2a

rmptuisrcui.rs

186 lines · 5.9 KB · Rust

1use crate::app::{App, SelectedTab};
2use ratatui::{
3 prelude::*,
4 widgets::{block::Title, *},
5};
6
7/// Renders the user interface widgets
8pub fn render(app: &mut App, frame: &mut Frame) {
9 // This is where you add new widgets.
10 // See the following resources:
11 // - https://docs.rs/ratatui/latest/ratatui/widgets/index.html
12 // - https://github.com/ratatui-org/ratatui/tree/master/examples
13
14 // Layout
15 let layout = Layout::default()
16 .direction(Direction::Vertical)
17 .constraints(vec![Constraint::Percentage(93), Constraint::Min(3)])
18 .split(frame.size());
19
20 match app.selected_tab {
21 SelectedTab::Queue => draw_queue(frame, app, layout[0]),
22 SelectedTab::Playlists => draw_playlists(frame, app, layout[0]),
23 SelectedTab::DirectoryBrowser => draw_directory_browser(frame, app, layout[0]),
24 }
25
26 draw_progress_bar(frame, app, layout[1]);
27}
28
29/// Draws the file tree browser
30fn draw_directory_browser(frame: &mut Frame, app: &mut App, size: Rect) {
31 let mut song_state = ListState::default();
32 let total_songs = app.conn.conn.stats().unwrap().songs.to_string();
33 let mut list: Vec<String> = vec![];
34 for (t, s) in app.browser.filetree.iter() {
35 if t == "file" {
36 list.push(s.to_string());
37 } else {
38 list.push(format!("[{}]", *s));
39 }
40 }
41 let list = List::new(list)
42 .block(
43 Block::default()
44 .title(format!("File Browser: {}", app.browser.path.clone()).bold())
45 .title(
46 Title::from(format!("Total Songs: {}", total_songs).bold().green())
47 .alignment(Alignment::Center),
48 )
49 .title(
50 Title::from(format!("Volume: {}%", app.conn.volume).bold().green())
51 .alignment(Alignment::Right),
52 )
53 .borders(Borders::ALL),
54 )
55 .highlight_style(
56 Style::new()
57 .fg(Color::Cyan)
58 .bg(Color::Black)
59 .add_modifier(Modifier::REVERSED),
60 )
61 .highlight_symbol(">>")
62 .repeat_highlight_symbol(true)
63 .scroll_padding(20);
64
65 song_state.select(Some(app.browser.selected));
66 frame.render_stateful_widget(list, size, &mut song_state);
67}
68
69/// draws playing queue
70fn draw_queue(frame: &mut Frame, app: &mut App, size: Rect) {
71 let mut queue_state = ListState::default();
72 let title = Block::default()
73 .title(Title::from("Play Queue".green().bold()))
74 .title(
75 Title::from(format!("Volume: {}%", app.conn.volume).bold().green())
76 .alignment(Alignment::Right),
77 );
78 let list = List::new(app.queue_list.list.clone())
79 .block(title.borders(Borders::ALL))
80 .highlight_style(
81 Style::new()
82 .fg(Color::Cyan)
83 .bg(Color::Black)
84 .add_modifier(Modifier::REVERSED),
85 )
86 .highlight_symbol(">>")
87 .repeat_highlight_symbol(true);
88
89 queue_state.select(Some(app.queue_list.index));
90 frame.render_stateful_widget(list, size, &mut queue_state);
91}
92
93/// draws all playlists
94fn draw_playlists(frame: &mut Frame, app: &mut App, size: Rect) {
95 let mut state = ListState::default();
96
97 let title = Block::default()
98 .title(Title::from("Playlist".green().bold()))
99 .title(
100 Title::from(format!("Volume: {}%", app.conn.volume).bold().green())
101 .alignment(Alignment::Right),
102 );
103
104 let list = List::new(app.pl_list.list.clone())
105 .block(title.borders(Borders::ALL))
106 .highlight_style(
107 Style::new()
108 .fg(Color::Cyan)
109 .bg(Color::Black)
110 .add_modifier(Modifier::REVERSED),
111 )
112 .highlight_symbol(">>")
113 .repeat_highlight_symbol(true);
114
115 state.select(Some(app.pl_list.index));
116 frame.render_stateful_widget(list, size, &mut state);
117}
118
119/// Draws Progress Bar
120fn draw_progress_bar(frame: &mut Frame, app: &mut App, size: Rect) {
121 // Get the current playing song
122 let song = app
123 .conn
124 .now_playing()
125 .unwrap()
126 .unwrap_or_else(|| "No Title Found".to_string());
127
128 // Get the current playing state
129 let mut state: String = String::new();
130 if !app.queue_list.list.is_empty() {
131 state = app.conn.state.clone();
132 state.push(':');
133 }
134
135 // Get the current modes
136 let mut modes_bottom: String = String::new();
137 // we do this to check if at least one mode is enabled so we can push "[]"
138 if app.conn.repeat | app.conn.random {
139 modes_bottom.push('r');
140 }
141
142 if !modes_bottom.is_empty() {
143 modes_bottom.clear();
144 modes_bottom.push('[');
145 if app.conn.repeat {
146 modes_bottom.push('r');
147 }
148 if app.conn.random {
149 modes_bottom.push('z');
150 }
151 modes_bottom.push(']');
152 };
153
154
155 // get the duration
156 let duration = if app.conn.total_duration.as_secs() != 0 {
157 format!(
158 "[{}/{}]",
159 humantime::format_duration(app.conn.elapsed),
160 humantime::format_duration(app.conn.total_duration)
161 )
162 } else {
163 "".to_string()
164 };
165
166 // Define the title
167 let title = Block::default()
168 .title(Title::from(format!("{}", state).red().bold()))
169 .title(Title::from(song.green().bold()))
170 .title(Title::from(duration.cyan().bold()).alignment(Alignment::Right))
171 .title(Title::from(format!("{}", modes_bottom)).position(block::Position::Bottom))
172 .borders(Borders::ALL);
173
174 let progress_bar = LineGauge::default()
175 .block(title.borders(Borders::ALL))
176 .gauge_style(
177 Style::default()
178 .fg(Color::Blue)
179 .bg(Color::Black)
180 .add_modifier(Modifier::BOLD),
181 )
182 .line_set(symbols::line::THICK)
183 .ratio(app.conn.get_progress_ratio());
184
185 frame.render_widget(progress_bar, size);
186}