Krolyxon
Commit a3a311f

rmptuisrcpopupsinput.rs

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