Krolyxon
Commit cf9c69a

rmptuisrcpopupsinput.rs

94 lines · 2.9 KB · Rust

1use ratatui::{Frame, layout::Rect};
2
3use super::{Popup, PopupState, frame_popup};
4use crate::{
5 action::{Context, ScreenId},
6 config::KeyCombo,
7 mpd::{Selection, commands},
8 screens::{Ctx, Effect, ScreenMessage},
9 tags::TagField,
10 ui::input::{InputEvent, LineInput},
11};
12
13/// What the entered text is for.
14#[derive(Clone, Debug)]
15pub enum InputPurpose {
16 NewPlaylist(Selection),
17 RenamePlaylist(String),
18 SaveQueue,
19 TagValue(TagField),
20}
21
22pub struct InputPopup {
23 title: String,
24 input: LineInput,
25 purpose: InputPurpose,
26}
27
28impl InputPopup {
29 pub fn new(title: impl Into<String>, initial: &str, purpose: InputPurpose) -> Self {
30 Self {
31 title: title.into(),
32 input: LineInput::new(initial),
33 purpose,
34 }
35 }
36
37 fn submit(&self, ctx: &mut Ctx) -> PopupState {
38 let value = self.input.text().trim().to_owned();
39 if value.is_empty() && !matches!(self.purpose, InputPurpose::TagValue(_)) {
40 return PopupState::Open;
41 }
42 match &self.purpose {
43 InputPurpose::NewPlaylist(selection) => {
44 if ctx.mpd.playlists.iter().any(|p| p.name == value) {
45 ctx.notify(format!("Added to existing playlist “{value}”"));
46 } else {
47 ctx.notify(format!("Created playlist “{value}”"));
48 }
49 ctx.client.exec_all(selection.add_to_playlist(&value));
50 }
51 InputPurpose::RenamePlaylist(from) => {
52 if *from != value {
53 ctx.client.exec(commands::rename(from, &value));
54 }
55 }
56 InputPurpose::SaveQueue => {
57 ctx.client.exec(commands::save(&value));
58 ctx.notify(format!("Saved the queue as “{value}”"));
59 }
60 InputPurpose::TagValue(field) => ctx.effects.push(Effect::Message(
61 ScreenId::TagEditor,
62 ScreenMessage::TagValue {
63 field: *field,
64 value,
65 },
66 )),
67 }
68 PopupState::Closed
69 }
70}
71
72impl Popup for InputPopup {
73 fn draw(&mut self, frame: &mut Frame, area: Rect, ctx: &Ctx) {
74 let width = (area.width * 3 / 5).max(40);
75 let inner = frame_popup(frame, area, width, 3, &self.title, ctx);
76 self.input.render(frame, inner, "", ctx.theme());
77 }
78
79 fn handle_key(&mut self, key: KeyCombo, ctx: &mut Ctx) -> PopupState {
80 match ctx.config.keymap.resolve(&[Context::Input], key) {
81 Some(action) => match self.input.apply(action) {
82 InputEvent::Submit => self.submit(ctx),
83 InputEvent::Cancel => PopupState::Closed,
84 _ => PopupState::Open,
85 },
86 None => {
87 if let Some(ch) = key.as_text() {
88 self.input.insert(ch);
89 }
90 PopupState::Open
91 }
92 }
93 }
94}