Skip to main content

aethermap_gui/views/
auto_switch.rs

1use crate::gui::{Message, State};
2use crate::theme;
3use iced::{
4    widget::{button, column, container, row, scrollable, text, text_input, Space},
5    Alignment, Element, Length,
6};
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct AutoSwitchRule {
11    pub app_id: String,
12    pub profile_name: String,
13    pub device_id: Option<String>,
14    pub layer_id: Option<usize>,
15}
16
17#[derive(Debug, Clone, Default)]
18pub struct AutoSwitchRulesView {
19    pub device_id: String,
20    pub rules: Vec<AutoSwitchRule>,
21    pub editing_rule: Option<usize>,
22    pub new_app_id: String,
23    pub new_profile_name: String,
24    pub new_layer_id: String,
25}
26
27pub fn view(state: &State) -> Element<'_, Message> {
28    let view = state.auto_switch_view.as_ref().unwrap();
29
30    let focus_display = row![
31        text("Current Focus:").size(14),
32        Space::with_width(8),
33        if let Some(ref focus) = state.current_focus {
34            container(text(focus).size(14))
35                .padding([4, 12])
36                .style(theme::styles::card)
37        } else {
38            container(text("Unknown").size(14).style(iced::theme::Text::Color(
39                iced::Color::from_rgb(0.6, 0.6, 0.6),
40            )))
41            .padding([4, 12])
42        },
43    ]
44    .spacing(4)
45    .align_items(Alignment::Center);
46
47    let rules_header = row![
48        text("Auto-Switch Rules").size(18),
49        Space::with_width(Length::Fill),
50        if view.editing_rule.is_some() {
51            button("Cancel")
52                .on_press(Message::EditAutoSwitchRule(usize::MAX))
53                .style(iced::theme::Button::Text)
54        } else {
55            button("Add Rule")
56                .on_press(Message::EditAutoSwitchRule(usize::MAX))
57                .style(iced::theme::Button::Primary)
58        },
59    ]
60    .align_items(Alignment::Center);
61
62    let rules_list = if view.rules.is_empty() {
63        column![
64            Space::with_height(20),
65            text("No rules configured")
66                .size(14)
67                .style(iced::theme::Text::Color(iced::Color::from_rgb(
68                    0.6, 0.6, 0.6
69                ))),
70            Space::with_height(8),
71            text("Add a rule to automatically switch profiles when windows gain focus")
72                .size(12)
73                .style(iced::theme::Text::Color(iced::Color::from_rgb(
74                    0.5, 0.5, 0.5
75                ))),
76        ]
77        .align_items(Alignment::Center)
78    } else {
79        let mut list = column![].spacing(8);
80        for (idx, rule) in view.rules.iter().enumerate() {
81            let is_editing = view.editing_rule == Some(idx);
82            let indicator: Element<'_, Message> = if is_editing {
83                container(text("\u{25b6}")).padding([0, 8]).into()
84            } else {
85                Space::with_width(20).into()
86            };
87            let rule_row = row![
88                indicator,
89                column![
90                    text(format!("App: {}", rule.app_id)).size(14),
91                    text(format!(
92                        "Profile: {}{}",
93                        rule.profile_name,
94                        rule.layer_id
95                            .map(|l| format!(" + Layer {}", l))
96                            .unwrap_or_default()
97                    ))
98                    .size(12),
99                ]
100                .spacing(2),
101                Space::with_width(Length::Fill),
102                button("Edit")
103                    .on_press(Message::EditAutoSwitchRule(idx))
104                    .style(iced::theme::Button::Text),
105                button("Delete")
106                    .on_press(Message::DeleteAutoSwitchRule(idx))
107                    .style(iced::theme::Button::Destructive),
108            ]
109            .spacing(8)
110            .align_items(Alignment::Center);
111            list = list.push(rule_row);
112        }
113        list
114    };
115
116    let edit_form = if view.editing_rule.is_some() {
117        Some(
118            column![
119                Space::with_height(20),
120                text(if view.editing_rule.unwrap_or(0) < view.rules.len() {
121                    "Edit Rule"
122                } else {
123                    "Add New Rule"
124                })
125                .size(16),
126                Space::with_height(12),
127                row![
128                    text("App ID:").size(14),
129                    Space::with_width(8),
130                    text_input("org.alacritty", &view.new_app_id)
131                        .on_input(Message::AutoSwitchAppIdChanged)
132                        .padding(8)
133                        .size(14),
134                    Space::with_width(8),
135                    button("Use Current")
136                        .on_press(Message::AutoSwitchUseCurrentApp)
137                        .style(iced::theme::Button::Secondary),
138                ]
139                .spacing(4)
140                .align_items(Alignment::Center),
141                Space::with_height(8),
142                row![
143                    text("Profile:").size(14),
144                    Space::with_width(8),
145                    text_input("default", &view.new_profile_name)
146                        .on_input(Message::AutoSwitchProfileNameChanged)
147                        .padding(8)
148                        .size(14),
149                ]
150                .spacing(4)
151                .align_items(Alignment::Center),
152                Space::with_height(8),
153                row![
154                    text("Layer (optional):").size(14),
155                    Space::with_width(8),
156                    text_input("0", &view.new_layer_id)
157                        .on_input(Message::AutoSwitchLayerIdChanged)
158                        .padding(8)
159                        .size(14),
160                ]
161                .spacing(4)
162                .align_items(Alignment::Center),
163                Space::with_height(12),
164                row![
165                    Space::with_width(Length::Fill),
166                    button("Save Rule")
167                        .on_press(Message::SaveAutoSwitchRule)
168                        .style(iced::theme::Button::Primary),
169                ]
170                .align_items(Alignment::Center),
171            ]
172            .spacing(4),
173        )
174    } else {
175        None
176    };
177
178    let mut content = column![
179        focus_display,
180        Space::with_height(20),
181        rules_header,
182        Space::with_height(12),
183        scrollable(rules_list).height(Length::Fixed(200.0)),
184    ]
185    .spacing(4);
186
187    if let Some(form) = edit_form {
188        content = content.push(form);
189    }
190
191    container(content)
192        .padding(20)
193        .width(Length::Fill)
194        .style(theme::styles::card)
195        .into()
196}