Skip to content

Commit 8497451

Browse files
committed
Handle custom home folder selection
1 parent fd60014 commit 8497451

File tree

2 files changed

+105
-115
lines changed

2 files changed

+105
-115
lines changed

src/create_distrobox_dialog.rs

Lines changed: 101 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
11
use adw::prelude::*;
22
use adw::subclass::prelude::*;
3+
use gtk::gio::File;
34
use gtk::{gio, glib};
45

56
use crate::distrobox::{self, CreateArgName, CreateArgs, Error};
67
use crate::root_store::RootStore;
78

9+
use std::path::PathBuf;
810
use std::{cell::RefCell, rc::Rc};
911

1012
use crate::distro_combo_row_item;
1113
use glib::clone;
1214
use gtk::glib::{derived_properties, Properties};
1315

16+
pub enum FileRowSelection {
17+
File,
18+
Folder
19+
}
1420
mod imp {
1521
use super::*;
1622

@@ -24,7 +30,13 @@ mod imp {
2430
pub content: gtk::Box,
2531
pub name_row: adw::EntryRow,
2632
pub image_row: adw::ComboRow,
27-
pub home_row: adw::SwitchRow,
33+
pub home_row_expander: adw::ExpanderRow,
34+
#[property(get, set, nullable)]
35+
pub home_folder: RefCell<Option<String>>,
36+
#[property(get, set, nullable)]
37+
pub assemble_file: RefCell<Option<String>>,
38+
#[property(get, set, nullable)]
39+
pub assemble_url: RefCell<Option<String>>,
2840
pub nvidia_row: adw::SwitchRow,
2941
pub init_row: adw::SwitchRow,
3042
pub volume_rows: Rc<RefCell<Vec<adw::EntryRow>>>,
@@ -38,6 +50,7 @@ mod imp {
3850
self.obj().set_title("Create a Distrobox");
3951
self.obj().set_content_width(480);
4052

53+
4154
let toolbar_view = adw::ToolbarView::new();
4255
let header = adw::HeaderBar::new();
4356

@@ -85,52 +98,25 @@ mod imp {
8598
self.image_row.set_title("Base Image");
8699
self.image_row.set_use_subtitle(true);
87100

88-
self.home_row.set_title("Mount Home Directory");
89-
90-
let file_chooser_fun = clone!(move || {
91-
// let file_chooser = gtk::FileChooserDialog::new(
92-
// Some("Select Home Directory"),
93-
// Some(&obj),
94-
// gtk::FileChooserAction::SelectFolder,
95-
// &[
96-
// ("Cancel", gtk::ResponseType::Cancel),
97-
// ("Select", gtk::ResponseType::Accept),
98-
// ],
99-
// );
100-
101-
// file_chooser.connect_response(
102-
// clone!(@weak home_row => move |file_chooser, response| {
103-
// if response == gtk::ResponseType::Accept {
104-
// if let Some(folder) = file_chooser.file() {
105-
// home_row.set_subtitle(&folder.path().unwrap().display().to_string());
106-
// }
107-
// }
108-
// file_chooser.close();
109-
// }),
110-
// );
111-
112-
// file_chooser.show();
101+
let obj = self.obj().clone();
102+
let home_row = self.obj().build_file_row("Select Home Directory", FileRowSelection::Folder, move |path| {
103+
obj.set_home_folder(Some(path.display().to_string()));
113104
});
114-
115-
let home_path_button = gtk::Button::from_icon_name("folder-symbolic");
116-
home_path_button.set_sensitive(false);
117-
home_path_button.set_valign(gtk::Align::Center);
118-
home_path_button.set_tooltip_text(Some("Select Home Directory"));
119-
home_path_button.add_css_class("flat");
120-
let file_chooser_fun_clone = file_chooser_fun.clone();
121-
self.home_row.connect_active_notify(clone!(
105+
self.home_row_expander.set_title("Custom Home Directory");
106+
self.home_row_expander.set_show_enable_switch(true);
107+
self.home_row_expander.set_enable_expansion(false);
108+
self.home_row_expander.add_row(&home_row);
109+
let obj = self.obj().clone();
110+
self.home_row_expander.connect_enable_expansion_notify(clone!(
122111
#[weak]
123-
home_path_button,
124-
move |row| {
125-
if row.is_active() {
126-
file_chooser_fun_clone();
112+
home_row,
113+
move |expander| {
114+
if !expander.enables_expansion() {
115+
obj.set_home_folder(None::<&str>);
127116
}
128-
home_path_button.set_sensitive(row.is_active());
117+
home_row.set_subtitle(obj.home_folder().as_deref().unwrap_or(""));
129118
}
130119
));
131-
home_path_button.connect_clicked(move |_| file_chooser_fun());
132-
133-
self.home_row.add_suffix(&home_path_button);
134120

135121
let nvidia_row = adw::SwitchRow::new();
136122
nvidia_row.set_title("NVIDIA Support");
@@ -140,7 +126,7 @@ mod imp {
140126

141127
preferences_group.add(&self.name_row);
142128
preferences_group.add(&self.image_row);
143-
preferences_group.add(&self.home_row);
129+
preferences_group.add(&self.home_row_expander);
144130
preferences_group.add(&nvidia_row);
145131
preferences_group.add(&init_row);
146132

@@ -180,50 +166,10 @@ mod imp {
180166
assemble_group.set_title("Assemble from File");
181167
assemble_group.set_description(Some("Create a container from an assemble file"));
182168

183-
let file_row = adw::ActionRow::new();
184-
file_row.set_title("Select File");
185-
file_row.set_subtitle("No file selected");
186-
file_row.set_activatable(true);
187-
188-
let file_icon = gtk::Image::from_icon_name("document-open-symbolic");
189-
file_row.add_suffix(&file_icon);
190-
191-
let obj = self.obj();
192-
file_row.connect_activated(clone!(
193-
#[weak]
194-
obj,
195-
#[weak]
196-
file_row,
197-
move |_| {
198-
let file_dialog = gtk::FileDialog::builder()
199-
.title("Select Assemble File")
200-
.modal(true)
201-
.build();
202-
203-
file_dialog.open(
204-
None::<&gtk::Window>,
205-
None::<&gio::Cancellable>,
206-
clone!(
207-
#[weak]
208-
obj,
209-
#[weak]
210-
file_row,
211-
move |res| {
212-
if let Ok(file) = res {
213-
if let Some(path) = file.path() {
214-
file_row.set_subtitle(&path.display().to_string());
215-
216-
obj.root_store()
217-
.assemble_container(&path.to_string_lossy());
218-
obj.close();
219-
}
220-
}
221-
}
222-
),
223-
);
224-
}
225-
));
226-
169+
let obj = self.obj().clone();
170+
let file_row = self.obj().build_file_row("Select Assemble File", FileRowSelection::File, move |path| {
171+
obj.set_assemble_file(Some(path.display().to_string()));
172+
});
227173
assemble_group.add(&file_row);
228174
assemble_page.append(&assemble_group);
229175

@@ -234,35 +180,27 @@ mod imp {
234180
create_btn.add_css_class("pill");
235181
create_btn.set_margin_top(12);
236182
create_btn.set_sensitive(false);
237-
238-
// Enable button when file is selected
239-
file_row.connect_subtitle_notify(clone!(
240-
#[weak]
241-
create_btn,
242-
move |row| {
243-
create_btn.set_sensitive(
244-
row.subtitle().map(|x| x.to_string())
245-
!= Some("No file selected".to_string()),
246-
);
247-
}
248-
));
183+
assemble_page.append(&create_btn);
249184

250185
// Handle create click
251186
let obj = self.obj();
252187
create_btn.connect_clicked(clone!(
253188
#[weak]
254189
obj,
255-
#[weak]
256-
file_row,
257190
move |_| {
258-
if let Some(path) = file_row.subtitle() {
191+
if let Some(path) = obj.assemble_file() {
259192
obj.root_store().assemble_container(path.as_ref());
260193
obj.close();
261194
}
262195
}
263196
));
264197

265-
assemble_page.append(&create_btn);
198+
// Enable button when file is selected
199+
self.obj().connect_assemble_file_notify(move |obj| {
200+
create_btn.set_sensitive(obj.assemble_file().is_some());
201+
});
202+
203+
266204

267205
// Create page for URL creation
268206
let url_page = gtk::Box::new(gtk::Orientation::Vertical, 12);
@@ -289,13 +227,14 @@ mod imp {
289227
create_btn.add_css_class("pill");
290228
create_btn.set_margin_top(12);
291229
create_btn.set_sensitive(false);
230+
url_page.append(&create_btn);
292231

293232
// Enable button when URL is entered
294233
url_row.connect_changed(clone!(
295234
#[weak]
296-
create_btn,
235+
obj,
297236
move |entry| {
298-
create_btn.set_sensitive(!entry.text().is_empty());
237+
obj.set_assemble_url(Some(entry.text()));
299238
}
300239
));
301240

@@ -304,16 +243,16 @@ mod imp {
304243
create_btn.connect_clicked(clone!(
305244
#[weak]
306245
obj,
307-
#[weak]
308-
url_row,
309246
move |_| {
310-
let url = url_row.text();
311-
obj.root_store().assemble_container(&url);
247+
obj.root_store().assemble_container(&obj.assemble_url().as_ref().unwrap());
312248
obj.close();
313249
}
314250
));
315251

316-
url_page.append(&create_btn);
252+
obj.connect_assemble_url_notify(move |obj| {
253+
create_btn.set_sensitive(obj.assemble_url().is_some());
254+
});
255+
317256

318257
// Add pages to view stack
319258
view_stack.add_titled(&gui_page, Some("create"), "Guided");
@@ -386,6 +325,57 @@ impl CreateDistroboxDialog {
386325
this
387326
}
388327

328+
pub fn build_file_row(&self, title: &str, selection: FileRowSelection, cb: impl Fn(PathBuf) + Clone + 'static) -> adw::ActionRow {
329+
let row = adw::ActionRow::new();
330+
row.set_title(title);
331+
row.set_subtitle("No file selected");
332+
row.set_activatable(true);
333+
334+
let file_icon = gtk::Image::from_icon_name("document-open-symbolic");
335+
row.add_suffix(&file_icon);
336+
337+
let title = title.to_owned();
338+
let dialog_cb = clone!(
339+
#[weak]
340+
row,
341+
move |res: Result<File, _>| {
342+
if let Ok(file) = res {
343+
if let Some(path) = file.path() {
344+
row.set_subtitle(&path.display().to_string());
345+
cb(path);
346+
}
347+
}
348+
}
349+
);
350+
row.connect_activated(
351+
move |_| {
352+
let file_dialog = gtk::FileDialog::builder()
353+
.title(&title)
354+
.modal(true)
355+
.build();
356+
let dialog_cb = dialog_cb.clone();
357+
match selection {
358+
FileRowSelection::File => {
359+
file_dialog.open(
360+
None::<&gtk::Window>,
361+
None::<&gio::Cancellable>,
362+
dialog_cb,
363+
);
364+
}
365+
FileRowSelection::Folder => {
366+
file_dialog.select_folder(
367+
None::<&gtk::Window>,
368+
None::<&gio::Cancellable>,
369+
dialog_cb,
370+
);
371+
}
372+
}
373+
}
374+
);
375+
row
376+
377+
}
378+
389379
pub fn update_create_args(&self) -> Result<(), Error> {
390380
let imp = self.imp();
391381
let image = imp
@@ -414,7 +404,7 @@ impl CreateDistroboxDialog {
414404
name,
415405
image: image.to_string(),
416406
nvidia: imp.nvidia_row.is_active(),
417-
home_path: imp.home_row.subtitle().map(|s| s.to_string()).unwrap(), // TODO: handle None,
407+
home_path: self.home_folder(),
418408
init: imp.init_row.is_active(),
419409
volumes,
420410
};

src/distrobox/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ impl CreateArgName {
182182
pub struct CreateArgs {
183183
pub init: bool,
184184
pub nvidia: bool,
185-
pub home_path: String,
185+
pub home_path: Option<String>,
186186
pub image: String,
187187
pub name: CreateArgName,
188188
pub volumes: Vec<String>,
@@ -707,8 +707,8 @@ impl Distrobox {
707707
if args.nvidia {
708708
cmd.arg("--nvidia");
709709
}
710-
if !args.home_path.is_empty() {
711-
cmd.arg("--home").arg(args.home_path);
710+
if let Some(home_path) = args.home_path {
711+
cmd.arg("--home").arg(home_path);
712712
}
713713
for volume in args.volumes {
714714
cmd.arg("--volume").arg(volume);
@@ -957,7 +957,7 @@ Categories=Utility;Network;
957957
image: "docker.io/library/ubuntu:latest".into(),
958958
init: true,
959959
nvidia: true,
960-
home_path: "/home/me".into(),
960+
home_path: Some("/home/me".into()),
961961
volumes: vec!["/mnt/sdb1".into(), "/mnt/sdb4".into()],
962962
..Default::default()
963963
};

0 commit comments

Comments
 (0)