refactor: share dashboard profile picker helpers

Deduplicate the profile strip's selected-item lookup and picker refresh
logic so save, apply, and delete flows all keep the dropdown and name field
in sync through the same helpers.
This commit is contained in:
2026-03-31 19:06:55 -04:00
parent 203457b31b
commit c26d9531f7
+40 -19
View File
@@ -151,8 +151,7 @@ pub(super) fn build_profiles_panel(ctx: &PageBuildContext) -> gtk4::Box {
let restore_button = restore_button.clone(); let restore_button = restore_button.clone();
let delete_button = delete_button.clone(); let delete_button = delete_button.clone();
restore_button.clone().connect_clicked(move |_| { restore_button.clone().connect_clicked(move |_| {
let idx = restore_dropdown.selected() as usize; let Some(path) = selected_profile_path(&restore_dropdown, &profile_paths) else {
let Some(path) = profile_paths.borrow().get(idx).cloned() else {
show_toast(&ctx.toast_overlay, "No profile selected"); show_toast(&ctx.toast_overlay, "No profile selected");
return; return;
}; };
@@ -171,15 +170,13 @@ pub(super) fn build_profiles_panel(ctx: &PageBuildContext) -> gtk4::Box {
&ctx.toast_overlay, &ctx.toast_overlay,
"Applied profile into the active config target", "Applied profile into the active config target",
); );
let selected_name = dropdown_selected_profile_name(&restore_dropdown); if let Some(selected) = refresh_profile_picker(
let selected = refresh_profile_picker(
&restore_dropdown, &restore_dropdown,
&restore_button, &restore_button,
&delete_button, &delete_button,
&profile_paths, &profile_paths,
selected_name.as_deref(), dropdown_selected_profile_name(&restore_dropdown).as_deref(),
); ) {
if let Some(selected) = selected {
persist_last_selected_profile_name(Some(&selected)); persist_last_selected_profile_name(Some(&selected));
} }
} }
@@ -196,8 +193,7 @@ pub(super) fn build_profiles_panel(ctx: &PageBuildContext) -> gtk4::Box {
let delete_button = delete_button.clone(); let delete_button = delete_button.clone();
let name_entry = name_entry.clone(); let name_entry = name_entry.clone();
delete_button.clone().connect_clicked(move |_| { delete_button.clone().connect_clicked(move |_| {
let idx = restore_dropdown.selected() as usize; let Some(path) = selected_profile_path(&restore_dropdown, &profile_paths) else {
let Some(path) = profile_paths.borrow().get(idx).cloned() else {
show_toast(&ctx.toast_overlay, "No profile selected"); show_toast(&ctx.toast_overlay, "No profile selected");
return; return;
}; };
@@ -227,18 +223,14 @@ pub(super) fn build_profiles_panel(ctx: &PageBuildContext) -> gtk4::Box {
match stored_profiles::delete_profile_path(&path) { match stored_profiles::delete_profile_path(&path) {
Ok(()) => { Ok(()) => {
let selected = refresh_profile_picker( sync_profile_picker_entry(
&restore_dropdown, &restore_dropdown,
&restore_button, &restore_button,
&delete_button, &delete_button,
&profile_paths, &profile_paths,
None, None,
&name_entry,
); );
if let Some(selected) = selected {
name_entry.set_text(&selected);
} else {
name_entry.set_text("");
}
show_toast( show_toast(
&ctx_clone.toast_overlay, &ctx_clone.toast_overlay,
&format!("Deleted profile {profile_name}"), &format!("Deleted profile {profile_name}"),
@@ -299,16 +291,14 @@ fn save_profile_from_dashboard(
let config = current_config_snapshot(ctx); let config = current_config_snapshot(ctx);
match stored_profiles::save_profile(profile_name, &config) { match stored_profiles::save_profile(profile_name, &config) {
Ok(path) => { Ok(path) => {
let selected = refresh_profile_picker( sync_profile_picker_entry(
restore_dropdown, restore_dropdown,
restore_button, restore_button,
delete_button, delete_button,
profile_paths, profile_paths,
Some(profile_name), Some(profile_name),
name_entry,
); );
if let Some(selected) = selected {
name_entry.set_text(&selected);
}
show_toast( show_toast(
&ctx.toast_overlay, &ctx.toast_overlay,
&format!("Saved active config target as profile {}", path.display()), &format!("Saved active config target as profile {}", path.display()),
@@ -394,6 +384,29 @@ fn refresh_profile_picker(
selected selected
} }
fn sync_profile_picker_entry(
dropdown: &gtk4::DropDown,
restore_button: &gtk4::Button,
delete_button: &gtk4::Button,
profile_paths: &Rc<RefCell<Vec<PathBuf>>>,
preferred_name: Option<&str>,
name_entry: &gtk4::Entry,
) -> Option<String> {
let selected = refresh_profile_picker(
dropdown,
restore_button,
delete_button,
profile_paths,
preferred_name,
);
if let Some(selected) = selected.as_deref() {
name_entry.set_text(selected);
} else {
name_entry.set_text("");
}
selected
}
fn last_selected_profile_name() -> Option<String> { fn last_selected_profile_name() -> Option<String> {
app_settings() app_settings()
.map(|settings| settings.string("last-profile-name").to_string()) .map(|settings| settings.string("last-profile-name").to_string())
@@ -414,6 +427,14 @@ fn dropdown_selected_profile_name(dropdown: &gtk4::DropDown) -> Option<String> {
.filter(|value| value != "No profiles found") .filter(|value| value != "No profiles found")
} }
fn selected_profile_path(
dropdown: &gtk4::DropDown,
profile_paths: &Rc<RefCell<Vec<PathBuf>>>,
) -> Option<PathBuf> {
let idx = dropdown.selected() as usize;
profile_paths.borrow().get(idx).cloned()
}
fn install_profile_dropdown_factory(dropdown: &gtk4::DropDown) { fn install_profile_dropdown_factory(dropdown: &gtk4::DropDown) {
let factory = gtk4::SignalListItemFactory::new(); let factory = gtk4::SignalListItemFactory::new();
factory.connect_setup(|_, item| { factory.connect_setup(|_, item| {