11use adw:: prelude:: * ;
22use adw:: subclass:: prelude:: * ;
3+ use gtk:: gio:: File ;
34use gtk:: { gio, glib} ;
45
56use crate :: distrobox:: { self , CreateArgName , CreateArgs , Error } ;
67use crate :: root_store:: RootStore ;
78
9+ use std:: path:: PathBuf ;
810use std:: { cell:: RefCell , rc:: Rc } ;
911
1012use crate :: distro_combo_row_item;
1113use glib:: clone;
1214use gtk:: glib:: { derived_properties, Properties } ;
1315
16+ pub enum FileRowSelection {
17+ File ,
18+ Folder
19+ }
1420mod 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 } ;
0 commit comments