Skip to content
Merged

Next #26

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
8 changes: 8 additions & 0 deletions data/com.ranfdev.DistroShelf.metainfo.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@
</screenshots>

<releases>
<release version="1.0.8" date="2025-05-28">
<description translate="no">
<ul>
<li>Fixed custom home path resolution</li>
<li>Add parsing of volume paths</li>
</ul>
</description>
</release>
<release version="1.0.7" date="2025-05-23">
<description translate="no">
<ul>
Expand Down
2 changes: 1 addition & 1 deletion meson.build
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
project('distroshelf', 'rust',
version: '1.0.7',
version: '1.0.8',
meson_version: '>= 1.0.0',
default_options: [ 'warning_level=2', 'werror=false', ],
)
Expand Down
2 changes: 1 addition & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pub static VERSION: &str = "1.0.7";
pub static VERSION: &str = "1.0.8";
pub static GETTEXT_PACKAGE: &str = "distroshelf";
pub static LOCALEDIR: &str = "/app/share/locale";
pub static PKGDATADIR: &str = "/app/share/distroshelf";
185 changes: 101 additions & 84 deletions src/create_distrobox_dialog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use adw::prelude::*;
use adw::subclass::prelude::*;
use gtk::gio::File;
use gtk::{gio, glib};
use tracing::error;

use crate::distrobox::{self, CreateArgName, CreateArgs, Error};
use crate::root_store::RootStore;
Expand All @@ -15,7 +16,7 @@ use gtk::glib::{derived_properties, Properties};

pub enum FileRowSelection {
File,
Folder
Folder,
}
mod imp {
use super::*;
Expand All @@ -41,7 +42,6 @@ mod imp {
pub init_row: adw::SwitchRow,
pub volume_rows: Rc<RefCell<Vec<adw::EntryRow>>>,
pub scrolled_window: gtk::ScrolledWindow,
pub current_create_args: RefCell<CreateArgs>,
}

#[derived_properties]
Expand All @@ -50,7 +50,6 @@ mod imp {
self.obj().set_title("Create a Distrobox");
self.obj().set_content_width(480);


let toolbar_view = adw::ToolbarView::new();
let header = adw::HeaderBar::new();

Expand Down Expand Up @@ -99,24 +98,29 @@ mod imp {
self.image_row.set_use_subtitle(true);

let obj = self.obj().clone();
let home_row = self.obj().build_file_row("Select Home Directory", FileRowSelection::Folder, move |path| {
obj.set_home_folder(Some(path.display().to_string()));
});
let home_row = self.obj().build_file_row(
"Select Home Directory",
FileRowSelection::Folder,
move |path| {
obj.set_home_folder(Some(path.display().to_string()));
},
);
self.home_row_expander.set_title("Custom Home Directory");
self.home_row_expander.set_show_enable_switch(true);
self.home_row_expander.set_enable_expansion(false);
self.home_row_expander.add_row(&home_row);
let obj = self.obj().clone();
self.home_row_expander.connect_enable_expansion_notify(clone!(
#[weak]
home_row,
move |expander| {
if !expander.enables_expansion() {
obj.set_home_folder(None::<&str>);
self.home_row_expander
.connect_enable_expansion_notify(clone!(
#[weak]
home_row,
move |expander| {
if !expander.enables_expansion() {
obj.set_home_folder(None::<&str>);
}
home_row.set_subtitle(obj.home_folder().as_deref().unwrap_or(""));
}
home_row.set_subtitle(obj.home_folder().as_deref().unwrap_or(""));
}
));
));

let nvidia_row = adw::SwitchRow::new();
nvidia_row.set_title("NVIDIA Support");
Expand All @@ -142,13 +146,13 @@ mod imp {
#[weak]
obj,
move |_| {
let res = obj.update_create_args();
obj.update_errors(&res);
if let Ok(()) = res {
obj.root_store().create_container(
obj.imp().current_create_args.borrow().clone(),
);
}
glib::MainContext::ref_thread_default().spawn_local(async move {
let res = obj.extract_create_args().await;
obj.update_errors(&res);
if let Ok(create_args) = res {
obj.root_store().create_container(create_args);
}
});
}
));
create_btn.add_css_class("suggested-action");
Expand All @@ -169,9 +173,13 @@ mod imp {
assemble_group.set_description(Some("Create a container from an assemble file"));

let obj = self.obj().clone();
let file_row = self.obj().build_file_row("Select Assemble File", FileRowSelection::File, move |path| {
obj.set_assemble_file(Some(path.display().to_string()));
});
let file_row = self.obj().build_file_row(
"Select Assemble File",
FileRowSelection::File,
move |path| {
obj.set_assemble_file(Some(path.display().to_string()));
},
);
assemble_group.add(&file_row);
assemble_page.append(&assemble_group);

Expand Down Expand Up @@ -202,8 +210,6 @@ mod imp {
create_btn.set_sensitive(obj.assemble_file().is_some());
});



// Create page for URL creation
let url_page = gtk::Box::new(gtk::Orientation::Vertical, 12);
url_page.set_margin_start(12);
Expand Down Expand Up @@ -246,7 +252,8 @@ mod imp {
#[weak]
obj,
move |_| {
obj.root_store().assemble_container(&obj.assemble_url().as_ref().unwrap());
obj.root_store()
.assemble_container(&obj.assemble_url().as_ref().unwrap());
obj.close();
}
));
Expand All @@ -255,7 +262,6 @@ mod imp {
create_btn.set_sensitive(obj.assemble_url().is_some());
});


// Add pages to view stack
view_stack.add_titled(&gui_page, Some("create"), "Guided");
view_stack.add_titled(&assemble_page, Some("assemble-file"), "From File");
Expand Down Expand Up @@ -327,58 +333,53 @@ impl CreateDistroboxDialog {
this
}

pub fn build_file_row(&self, title: &str, selection: FileRowSelection, cb: impl Fn(PathBuf) + Clone + 'static) -> adw::ActionRow {
let row = adw::ActionRow::new();
row.set_title(title);
row.set_subtitle("No file selected");
row.set_activatable(true);

let file_icon = gtk::Image::from_icon_name("document-open-symbolic");
row.add_suffix(&file_icon);

let title = title.to_owned();
let dialog_cb = clone!(
#[weak]
row,
move |res: Result<File, _>| {
if let Ok(file) = res {
if let Some(path) = file.path() {
row.set_subtitle(&path.display().to_string());
cb(path);
}
}
}
);
row.connect_activated(
move |_| {
let file_dialog = gtk::FileDialog::builder()
.title(&title)
.modal(true)
.build();
let dialog_cb = dialog_cb.clone();
match selection {
FileRowSelection::File => {
file_dialog.open(
None::<&gtk::Window>,
None::<&gio::Cancellable>,
dialog_cb,
);
}
FileRowSelection::Folder => {
file_dialog.select_folder(
None::<&gtk::Window>,
None::<&gio::Cancellable>,
dialog_cb,
);
}
pub fn build_file_row(
&self,
title: &str,
selection: FileRowSelection,
cb: impl Fn(PathBuf) + Clone + 'static,
) -> adw::ActionRow {
let row = adw::ActionRow::new();
row.set_title(title);
row.set_subtitle("No file selected");
row.set_activatable(true);

let file_icon = gtk::Image::from_icon_name("document-open-symbolic");
row.add_suffix(&file_icon);

let title = title.to_owned();
let dialog_cb = clone!(
#[weak]
row,
move |res: Result<File, _>| {
if let Ok(file) = res {
if let Some(path) = file.path() {
row.set_subtitle(&path.display().to_string());
cb(path);
}
}
);
row

}
);
row.connect_activated(move |_| {
let file_dialog = gtk::FileDialog::builder().title(&title).modal(true).build();
let dialog_cb = dialog_cb.clone();
match selection {
FileRowSelection::File => {
file_dialog.open(None::<&gtk::Window>, None::<&gio::Cancellable>, dialog_cb);
}
FileRowSelection::Folder => {
file_dialog.select_folder(
None::<&gtk::Window>,
None::<&gio::Cancellable>,
dialog_cb,
);
}
}
});
row
}

pub fn update_create_args(&self) -> Result<(), Error> {
pub async fn extract_create_args(&self) -> Result<CreateArgs, Error> {
let imp = self.imp();
let image = imp
.image_row
Expand All @@ -393,32 +394,45 @@ impl CreateDistroboxDialog {
.iter()
.filter_map(|entry| {
if !entry.text().is_empty() {
Some(entry.text().to_string())
match entry.text().parse::<distrobox::Volume>() {
Ok(volume) => Some(Ok(volume)),
Err(e) => Some(Err(e)),
}
} else {
None
}
})
.collect::<Vec<_>>();
.collect::<Result<Vec<_>, _>>()?;

let name = CreateArgName::new(&imp.name_row.text())?;

dbg!(&self.home_folder());
let create_args = CreateArgs {
name,
image: image.to_string(),
nvidia: imp.nvidia_row.is_active(),
home_path: self.home_folder(),
home_path: if let Some(home) = self.home_folder() {
Some(
self.root_store()
.resolve_host_path(&home)
.await
.map_err(|e| Error::InvalidField("home".to_string(), e.to_string()))?,
)
} else {
None
},
init: imp.init_row.is_active(),
volumes,
};
dbg!(&create_args);

self.imp().current_create_args.replace(create_args);
Ok(())
Ok(create_args)
}

pub fn build_volumes_group(&self) -> adw::PreferencesGroup {
let volumes_group = adw::PreferencesGroup::new();
volumes_group.set_title("Volumes");
volumes_group.set_description(Some("Specify volumes in the format 'dest_dir:source_dir'"));
volumes_group.set_description(Some("Specify volumes in the format 'host_path:container_path'"));

let add_volume_button = adw::ButtonRow::builder().title("Add Volume").build();
add_volume_button.connect_activated(clone!(
Expand Down Expand Up @@ -462,10 +476,13 @@ impl CreateDistroboxDialog {
volumes_group
}

fn update_errors(&self, res: &Result<(), distrobox::Error>) {
fn update_errors<T>(&self, res: &Result<T, distrobox::Error>) {
let imp = self.imp();
imp.name_row.remove_css_class("error");
imp.name_row.set_tooltip_text(None);
if let Err(ref e) = res {
error!(error = %e, "CreateDistroboxDialog: update_errors");
}
match res {
Err(distrobox::Error::InvalidField(field, msg)) if field == "name" => {
imp.name_row.add_css_class("error");
Expand Down
Loading
Loading