Krolyxon
Commit 96dd350

rmptuisrcpopupsadd_to_playlist.rs

115 lines · 3.3 KB · Rust

1use ratatui::{
2 Frame,
3 layout::{Constraint, Rect},
4 text::Span,
5 widgets::{Block, Row},
6};
7
8use super::{InputPopup, InputPurpose, Popup, PopupState, frame_popup};
9use crate::{
10 action::{Action, Context},
11 config::KeyCombo,
12 mpd::Selection,
13 screens::Ctx,
14 ui::list::ListView,
15};
16
17enum Choice {
18 Queue,
19 NewPlaylist,
20 Playlist(String),
21}
22
23/// Chooses where to add a selection: the queue, a new or an existing playlist.
24pub struct AddToPlaylistPopup {
25 selection: Selection,
26 choices: Vec<Choice>,
27 list: ListView,
28}
29
30impl AddToPlaylistPopup {
31 pub fn new(selection: Selection, ctx: &Ctx) -> Self {
32 let mut choices = vec![Choice::Queue, Choice::NewPlaylist];
33 choices.extend(
34 ctx.mpd
35 .playlists
36 .iter()
37 .map(|p| Choice::Playlist(p.name.clone())),
38 );
39 Self {
40 selection,
41 choices,
42 list: ListView::default(),
43 }
44 }
45
46 fn choose(&mut self, ctx: &mut Ctx) -> PopupState {
47 let Some(choice) = self
48 .list
49 .selected(self.choices.len())
50 .and_then(|i| self.choices.get(i))
51 else {
52 return PopupState::Open;
53 };
54 match choice {
55 Choice::Queue => {
56 ctx.client.exec_all(self.selection.add_to_queue());
57 ctx.notify("Added to the queue");
58 }
59 Choice::NewPlaylist => {
60 ctx.popup(InputPopup::new(
61 "New playlist",
62 "",
63 InputPurpose::NewPlaylist(self.selection.clone()),
64 ));
65 }
66 Choice::Playlist(name) => {
67 ctx.client.exec_all(self.selection.add_to_playlist(name));
68 ctx.notify(format!("Added to playlist “{name}”"));
69 }
70 }
71 PopupState::Closed
72 }
73}
74
75impl Popup for AddToPlaylistPopup {
76 fn draw(&mut self, frame: &mut Frame, area: Rect, ctx: &Ctx) {
77 let height = self.choices.len().min(15) as u16 + 2;
78 let inner = frame_popup(frame, area, 44, height, "Add to", ctx);
79 let theme = ctx.theme();
80 let choices = &self.choices;
81 self.list.render(
82 frame,
83 inner,
84 Block::new(),
85 None,
86 &[Constraint::Fill(1)],
87 choices.len(),
88 true,
89 theme,
90 |i| {
91 Row::new([match &choices[i] {
92 Choice::Queue => Span::styled("Current queue", theme.accent()),
93 Choice::NewPlaylist => Span::styled("New playlist…", theme.accent()),
94 Choice::Playlist(name) => Span::styled(name.clone(), theme.text()),
95 }])
96 },
97 );
98 }
99
100 fn handle_key(&mut self, key: KeyCombo, ctx: &mut Ctx) -> PopupState {
101 match ctx
102 .config
103 .keymap
104 .resolve(&[Context::Popup, Context::Navigation], key)
105 {
106 Some(Action::Close) => PopupState::Closed,
107 Some(Action::Activate | Action::Right) => self.choose(ctx),
108 Some(action) => {
109 self.list.navigate(action, self.choices.len());
110 PopupState::Open
111 }
112 None => PopupState::Open,
113 }
114 }
115}