Krolyxon
Commit 815a27a

rmptuisrcpopupsadd_to_playlist.rs

114 lines · 3.2 KB · Rust

1use ratatui::{
2 Frame,
3 layout::{Constraint, Rect},
4 text::Span,
5 widgets::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 None,
85 &[Constraint::Fill(1)],
86 choices.len(),
87 true,
88 theme,
89 |i| {
90 Row::new([match &choices[i] {
91 Choice::Queue => Span::styled("Current queue", theme.header()),
92 Choice::NewPlaylist => Span::styled("New playlist…", theme.header()),
93 Choice::Playlist(name) => Span::styled(name.clone(), theme.text()),
94 }])
95 },
96 );
97 }
98
99 fn handle_key(&mut self, key: KeyCombo, ctx: &mut Ctx) -> PopupState {
100 match ctx
101 .config
102 .keymap
103 .resolve(&[Context::Popup, Context::Navigation], key)
104 {
105 Some(Action::Close) => PopupState::Closed,
106 Some(Action::Activate | Action::Right) => self.choose(ctx),
107 Some(action) => {
108 self.list.navigate(action, self.choices.len());
109 PopupState::Open
110 }
111 None => PopupState::Open,
112 }
113 }
114}