Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions locales/gui.yml
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,10 @@ gui.togtkbox_test:
en: "ToGtkBox Test"
ru: "Тест ToGtkBox"
zh-CN: "ToGtkBox 测试"
gui.confirm:
en: "Confirm"
ru: "Подтвердить"
zh-CN: "确认"
gui.history_manager:
en: "History Manager"
ru: "Менеджер истории"
Expand Down
16 changes: 16 additions & 0 deletions locales/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ main.failed_to_create__:
en: "Failed to create %{file}: %{error}"
ru: "Не удалось создать %{file}: %{error}"
zh-CN: "无法创建 %{file}: %{error}"
main.confirm_modify_main_config:
en: "Modify Hyprland Config"
ru: "Изменить конфигурацию Hyprland"
zh-CN: "修改 Hyprland 配置"
main.confirm_modify_main_config_text:
en: "HyprViz needs to add or update a 'source' line in your main hyprland.conf to apply settings. This will reload Hyprland. Proceed?"
ru: "HyprViz необходимо добавить или обновить строку 'source' в вашем основном hyprland.conf для применения настроек. Это перезагрузит конфигурацию Hyprland. Продолжить?"
zh-CN: "HyprViz 需要在主 hyprland.conf 中添加或更新 'source' 行以应用设置。这将重载 Hyprland 配置。是否继续?"
main.saving_failed:
en: "Saving failed"
ru: "Не удалось сохранить"
Expand All @@ -51,6 +59,14 @@ main.failed_to_add_source_line_to__:
en: "Failed to add 'source = ./hyprviz.conf' to %{file}: %{error}"
ru: "Не удалось добавить 'source = ./hyprviz.conf' в %{file}: %{error}"
zh-CN: "无法将 'source = ./hyprviz.conf' 添加到 %{file}: %{error}"
main.integration_skipped:
en: "Integration Skipped"
ru: "Интеграция пропущена"
zh-CN: "集成已跳过"
main.integration_skipped_text:
en: "The 'source' line was not added to hyprland.conf. HyprViz settings will be saved to hyprviz.conf but will NOT take effect in Hyprland until you manually add 'source = ./hyprviz.conf' or confirm this dialog on next launch."
ru: "Строка 'source' не была добавлена в hyprland.conf. Настройки HyprViz будут сохраняться в hyprviz.conf, но НЕ вступят в силу в Hyprland, пока вы вручную не добавите 'source = ./hyprviz.conf' или не подтвердите этот диалог при следующем запуске."
zh-CN: "未将 'source' 行添加到 hyprland.conf。HyprViz 设置将保存到 hyprviz.conf,但在您手动添加 'source = ./hyprviz.conf' 或在下次启动时确认此对话框之前,它们不会在 Hyprland 中生效。"
main.profile_not_found:
en: "Profile not found"
ru: "Профиль не найден"
Expand Down
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ If you manage your NixOS configuration with flakes, add hyprviz as an input in y
- [x] Add fancy editors for all options
- [x] Add symlink support
- [x] Add CTRL-Z/CTRL-Y support
- [ ] Add confirmation dialog for editing main hyprland.conf
- [x] Add confirmation dialog for editing main hyprland.conf
- [ ] Add row actions (discard/remove) for individual options
- [ ] Add support for waybar, swaync, hyprlock...
- [x] Improve GUI
Expand Down
31 changes: 31 additions & 0 deletions src/gui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1132,6 +1132,37 @@ along with this program; if not, see
);
}

pub fn show_confirmation_dialog<F, G>(
&self,
title: &str,
text: &str,
on_confirm: F,
on_cancel: G,
) where
F: FnOnce() + 'static,
G: FnOnce() + 'static,
{
let dialog = AlertDialog::builder()
.message(title)
.detail(text)
.buttons([&*t!("gui.cancel"), &*t!("gui.confirm")])
.modal(true)
.build();

dialog.choose(
Some(&self.window),
None::<&gio::Cancellable>,
move |res: Result<i32, glib::Error>| {
// GTK returns the index of the pressed button: 0 = Cancel, 1 = Confirm
if res.ok() == Some(1) {
on_confirm();
} else {
on_cancel();
}
},
);
}

pub fn show_history_manager(gui: Rc<RefCell<ConfigGUI>>) {
let window = Window::builder()
.title(t!("gui.history_manager"))
Expand Down
103 changes: 76 additions & 27 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ fn build_ui(app: &Application) {
let gui = Rc::new(RefCell::new(ConfigGUI::new(app)));
gui::ConfigGUI::setup_ui_events(Rc::clone(&gui));

let is_programmatic_switch = Rc::new(std::cell::Cell::new(false));
let last_confirmed_index = Rc::new(std::cell::Cell::new(0u32));

let config_path_full = get_config_path(false, "Default");

if !config_path_full.exists() {
Expand Down Expand Up @@ -154,22 +157,35 @@ fn build_ui(app: &Application) {
}
}

match atomic_write(&config_path_full, &updated_config_str) {
Ok(_) => {
println!("Added 'source = ./hyprviz.conf' to ~/{}", CONFIG_PATH);
reload_hyprland();
}
Err(e) => {
gui.borrow().custom_error_popup_critical(
&t!("main.saving_failed"),
&t!(
"main.failed_to_add_source_line_to__",
file = CONFIG_PATH,
error = e
),
let config_path_full_clone = config_path_full.clone();
let gui_clone_confirm = Rc::clone(&gui);
let gui_clone_cancel = Rc::clone(&gui);
gui.borrow().show_confirmation_dialog(
&t!("main.confirm_modify_main_config"),
&t!("main.confirm_modify_main_config_text"),
move || match atomic_write(&config_path_full_clone, &updated_config_str) {
Ok(()) => {
println!("Added 'source = ./hyprviz.conf' to ~/{}", CONFIG_PATH);
reload_hyprland();
}
Err(e) => {
gui_clone_confirm.borrow().custom_error_popup_critical(
&t!("main.saving_failed"),
&t!(
"main.failed_to_add_source_line_to__",
file = CONFIG_PATH,
error = e
),
);
}
},
move || {
gui_clone_cancel.borrow().custom_info_popup(
&t!("main.integration_skipped"),
&t!("main.integration_skipped_text"),
);
}
}
},
);
}

let profile = get_current_profile(&config_str);
Expand Down Expand Up @@ -261,23 +277,56 @@ fn build_ui(app: &Application) {
}

let gui_clone = Rc::clone(&gui);
let is_programmatic_switch_clone = Rc::clone(&is_programmatic_switch);
let last_confirmed_index_clone = Rc::clone(&last_confirmed_index);
let config_path_full_clone = config_path_full.clone();
gui.borrow()
.profile_dropdown
.connect_selected_notify(move |dropdown| {
let selected_index = dropdown.selected();
if is_programmatic_switch_clone.get() {
return;
}

let new_index = dropdown.selected();
let prev_index = last_confirmed_index_clone.get();
let model = dropdown.model().unwrap();

if let Some(item) = model.item(selected_index)
let profile_name = if let Some(item) = model.item(new_index)
&& let Some(string_object) = item.downcast_ref::<StringObject>()
{
let profile_name = string_object.string().as_str().to_string();
match update_source_line(&config_path_full, &profile_name) {
string_object.string().as_str().to_string()
} else {
return;
};

let last_confirmed_index_clone_clone = Rc::clone(&last_confirmed_index_clone);
let config_path_full_clone_clone = config_path_full_clone.clone();
let gui_clone_clone = Rc::clone(&gui_clone);
let is_programmatic_switch_clone_clone_confirm =
Rc::clone(&is_programmatic_switch_clone);
let dropdown_clone_confirm = dropdown.clone();

let is_programmatic_switch_clone_clone_cancel =
Rc::clone(&is_programmatic_switch_clone);
let dropdown_clone_cancel = dropdown.clone();

gui_clone.borrow().show_confirmation_dialog(
&t!("main.confirm_modify_main_config"),
&t!("main.confirm_modify_main_config_text"),
move || match update_source_line(&config_path_full_clone_clone, &profile_name) {
Ok(_) => {
println!("Updated source line to profile: {}", profile_name);
reload_hyprland();
last_confirmed_index_clone_clone.set(new_index);
glib::MainContext::default().spawn_local(async move {
gui_clone_clone.borrow_mut().reload_ui(true);
});
}
Err(e) => {
gui_clone.borrow().custom_error_popup(
is_programmatic_switch_clone_clone_confirm.set(true);
dropdown_clone_confirm.set_selected(prev_index);
is_programmatic_switch_clone_clone_confirm.set(false);
gui_clone_clone.borrow().custom_error_popup(
&t!("main.profile_switch_failed"),
&t!(
"main.failed_to_update_config_for_profile__",
Expand All @@ -286,13 +335,13 @@ fn build_ui(app: &Application) {
),
);
}
}
let gui = Rc::clone(&gui_clone);

glib::MainContext::default().spawn_local(async move {
gui.borrow_mut().reload_ui(true);
});
}
},
move || {
is_programmatic_switch_clone_clone_cancel.set(true);
dropdown_clone_cancel.set_selected(prev_index);
is_programmatic_switch_clone_clone_cancel.set(false);
},
);
});
}

Expand Down