danceinterpreter_rs/ui/config_window/
dialog.rs1use crate::dataloading::dataprovider::ItemSource;
2use crate::{DanceInterpreter, DialogMessage, Message, StaticsMessage};
3use iced::alignment::Alignment;
4use iced::widget::{Space, button, column as col, container, mouse_area, opaque, row, stack, text};
5use iced::{Color, Element, Length, Theme};
6
7pub enum DialogState {
8 Delete(ItemSource),
9 MergeStatic { old_name: String, new_name: String },
10}
11
12pub fn build_action_dialog<'a>(
13 title: String,
14 target: String,
15 confirm_text: String,
16 confirm_style: impl Fn(&Theme, button::Status) -> button::Style + 'static,
17 cancel_msg: Message,
18 confirm_msg: Message,
19) -> Element<'a, Message> {
20 let cancel_msg_clone = cancel_msg.clone();
21 let card = container(
22 col![
23 text(title).size(20),
24 text(target),
25 row![
26 button(text("Cancel").align_x(Alignment::Center))
27 .padding([4, 8])
28 .style(button::secondary)
29 .on_press(cancel_msg)
30 .width(Length::Fill),
31 button(text(confirm_text).align_x(Alignment::Center))
32 .padding([4, 8])
33 .style(confirm_style)
34 .on_press(confirm_msg)
35 .width(Length::Fill),
36 ]
37 .spacing(10),
38 ]
39 .spacing(15)
40 .width(Length::Fixed(360.0)),
41 )
42 .padding(20)
43 .style(|t: &Theme| {
44 let palette = t.extended_palette();
45 container::Style::default()
46 .background(palette.background.base.color)
47 .border(iced::Border {
48 color: palette.background.strong.color,
49 width: 1.0,
50 radius: 8.0.into(),
51 })
52 });
53
54 let backdrop = mouse_area(
55 container(Space::new().width(Length::Fill).height(Length::Fill))
56 .width(Length::Fill)
57 .height(Length::Fill)
58 .style(|_t: &Theme| {
59 container::Style::default().background(Color::from_rgba(0.0, 0.0, 0.0, 0.5))
60 }),
61 )
62 .on_press(cancel_msg_clone);
63
64 let centered_card = container(opaque(card))
65 .width(Length::Fill)
66 .height(Length::Fill)
67 .align_x(Alignment::Center)
68 .align_y(Alignment::Center);
69
70 opaque(stack![backdrop, centered_card])
71}
72
73pub fn build_dialog<'a>(
74 state: &'a DialogState,
75 dance_interpreter: &'a DanceInterpreter,
76) -> Element<'a, Message> {
77 match state {
78 DialogState::Delete(source) => {
79 let target_name = match source {
80 ItemSource::Playlist(i) => dance_interpreter
81 .data_provider
82 .playlist()
83 .get(*i)
84 .map(|item| item.song.title.clone())
85 .unwrap_or_default(),
86 ItemSource::Static(name) => dance_interpreter
87 .data_provider
88 .statics()
89 .get(name)
90 .map(|s| s.name.clone())
91 .unwrap_or(name.clone()),
92 _ => String::new(),
93 };
94 build_action_dialog(
95 "Delete item?".to_string(),
96 target_name,
97 "Delete".to_string(),
98 button::danger,
99 Message::Dialog(DialogMessage::CancelDelete),
100 Message::Dialog(DialogMessage::ConfirmDelete),
101 )
102 }
103 DialogState::MergeStatic { old_name, new_name } => build_action_dialog(
104 "Merge Statics?".to_string(),
105 format!(
106 "A static named '{}' already exists.\nMerge '{}' into it?",
107 new_name, old_name
108 ),
109 "Merge".to_string(),
110 button::primary,
111 Message::Dialog(DialogMessage::Cancel),
112 Message::Statics(StaticsMessage::ConfirmMerge(
113 old_name.clone(),
114 new_name.clone(),
115 )),
116 ),
117 }
118}