158 lines
4.9 KiB
Rust
158 lines
4.9 KiB
Rust
use adw::prelude::*;
|
|
use gtk::gio;
|
|
|
|
use crate::config::APP_ID;
|
|
|
|
pub fn show_preferences_dialog(parent: &impl IsA<gtk::Widget>) {
|
|
let dialog = adw::PreferencesDialog::new();
|
|
dialog.set_title("Preferences");
|
|
|
|
let settings = gio::Settings::new(APP_ID);
|
|
|
|
// --- General page ---
|
|
let general_page = adw::PreferencesPage::builder()
|
|
.title("General")
|
|
.icon_name("emblem-system-symbolic")
|
|
.build();
|
|
|
|
// Appearance group
|
|
let appearance_group = adw::PreferencesGroup::builder()
|
|
.title("Appearance")
|
|
.build();
|
|
|
|
let theme_row = adw::ComboRow::builder()
|
|
.title("Color Scheme")
|
|
.subtitle("Choose light, dark, or follow system preference")
|
|
.build();
|
|
|
|
let model = gtk::StringList::new(&["Follow System", "Light", "Dark"]);
|
|
theme_row.set_model(Some(&model));
|
|
|
|
let current = settings.string("color-scheme");
|
|
theme_row.set_selected(match current.as_str() {
|
|
"force-light" => 1,
|
|
"force-dark" => 2,
|
|
_ => 0,
|
|
});
|
|
|
|
let settings_clone = settings.clone();
|
|
theme_row.connect_selected_notify(move |row| {
|
|
let value = match row.selected() {
|
|
1 => "force-light",
|
|
2 => "force-dark",
|
|
_ => "default",
|
|
};
|
|
settings_clone.set_string("color-scheme", value).ok();
|
|
});
|
|
|
|
appearance_group.add(&theme_row);
|
|
general_page.add(&appearance_group);
|
|
|
|
// Scan Locations group
|
|
let scan_group = adw::PreferencesGroup::builder()
|
|
.title("Scan Locations")
|
|
.description("Directories to scan for AppImage files")
|
|
.build();
|
|
|
|
let dirs = settings.strv("scan-directories");
|
|
let dir_list_box = gtk::ListBox::new();
|
|
dir_list_box.add_css_class("boxed-list");
|
|
dir_list_box.set_selection_mode(gtk::SelectionMode::None);
|
|
|
|
for dir in &dirs {
|
|
add_directory_row(&dir_list_box, &dir, &settings);
|
|
}
|
|
|
|
scan_group.add(&dir_list_box);
|
|
|
|
// Add location button
|
|
let add_button = gtk::Button::builder()
|
|
.label("Add Location")
|
|
.build();
|
|
add_button.add_css_class("flat");
|
|
|
|
let settings_add = settings.clone();
|
|
let list_box_ref = dir_list_box.clone();
|
|
let dialog_weak = dialog.downgrade();
|
|
add_button.connect_clicked(move |_| {
|
|
let file_dialog = gtk::FileDialog::builder()
|
|
.title("Choose a directory")
|
|
.modal(true)
|
|
.build();
|
|
|
|
let settings_ref = settings_add.clone();
|
|
let list_ref = list_box_ref.clone();
|
|
let dlg = dialog_weak.upgrade();
|
|
// Get the root window as the transient parent for the file dialog
|
|
let parent_window: Option<gtk::Window> = dlg
|
|
.as_ref()
|
|
.and_then(|d| d.root())
|
|
.and_then(|r| r.downcast::<gtk::Window>().ok());
|
|
file_dialog.select_folder(
|
|
parent_window.as_ref(),
|
|
None::<&gio::Cancellable>,
|
|
move |result| {
|
|
if let Ok(file) = result {
|
|
if let Some(path) = file.path() {
|
|
let path_str = path.to_string_lossy().to_string();
|
|
|
|
let mut current_dirs: Vec<String> = settings_ref
|
|
.strv("scan-directories")
|
|
.iter()
|
|
.map(|s| s.to_string())
|
|
.collect();
|
|
|
|
if !current_dirs.contains(&path_str) {
|
|
current_dirs.push(path_str.clone());
|
|
let refs: Vec<&str> =
|
|
current_dirs.iter().map(|s| s.as_str()).collect();
|
|
settings_ref.set_strv("scan-directories", refs).ok();
|
|
|
|
add_directory_row(&list_ref, &path_str, &settings_ref);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
);
|
|
});
|
|
|
|
scan_group.add(&add_button);
|
|
general_page.add(&scan_group);
|
|
|
|
dialog.add(&general_page);
|
|
dialog.present(Some(parent));
|
|
}
|
|
|
|
fn add_directory_row(list_box: >k::ListBox, dir: &str, settings: &gio::Settings) {
|
|
let row = adw::ActionRow::builder()
|
|
.title(dir)
|
|
.build();
|
|
|
|
let remove_btn = gtk::Button::builder()
|
|
.icon_name("edit-delete-symbolic")
|
|
.valign(gtk::Align::Center)
|
|
.tooltip_text("Remove")
|
|
.build();
|
|
remove_btn.add_css_class("flat");
|
|
|
|
let list_ref = list_box.clone();
|
|
let settings_ref = settings.clone();
|
|
let dir_str = dir.to_string();
|
|
let row_ref = row.clone();
|
|
remove_btn.connect_clicked(move |_| {
|
|
let current_dirs: Vec<String> = settings_ref
|
|
.strv("scan-directories")
|
|
.iter()
|
|
.map(|s| s.to_string())
|
|
.filter(|s| s != &dir_str)
|
|
.collect();
|
|
let refs: Vec<&str> = current_dirs.iter().map(|s| s.as_str()).collect();
|
|
settings_ref.set_strv("scan-directories", refs).ok();
|
|
|
|
list_ref.remove(&row_ref);
|
|
});
|
|
|
|
row.add_suffix(&remove_btn);
|
|
list_box.append(&row);
|
|
}
|