@@ -2,7 +2,6 @@ use adw::prelude::*;
22use adw:: subclass:: prelude:: * ;
33use gtk:: gio:: File ;
44use gtk:: { gio, glib} ;
5- use std:: cell:: Cell ;
65use std:: time:: Duration ;
76use tracing:: error;
87
@@ -39,16 +38,11 @@ mod imp {
3938 pub toolbar_view : adw:: ToolbarView ,
4039 pub toast_overlay : adw:: ToastOverlay ,
4140 pub name_row : adw:: EntryRow ,
42- #[ property( get, set) ]
43- pub url_validated : Cell < bool > ,
4441 pub image_row : adw:: ActionRow ,
4542 pub images_model : gtk:: StringList ,
4643 pub selected_image : RefCell < String > ,
4744 pub prefill_query : RefCell < Option < Query < Option < String > > > > ,
48- pub url_validation_query : RefCell < Option < Query < bool > > > ,
4945 pub ini_content_query : RefCell < Option < Query < String > > > ,
50- #[ property( get, set) ]
51- pub ini_approved : Cell < bool > ,
5246 pub home_row_expander : adw:: ExpanderRow ,
5347 #[ property( get, set, nullable) ]
5448 pub home_folder : RefCell < Option < String > > ,
@@ -479,28 +473,21 @@ impl CreateDistroboxDialog {
479473 let url_row = adw:: EntryRow :: new ( ) ;
480474 url_row. set_title ( & gettext ( "URL" ) ) ;
481475 url_row. set_text ( "https://example.com/container.ini" ) ;
482- url_row. set_show_apply_button ( true ) ;
483476
484477 url_group. add ( & url_row) ;
485478 content. append ( & url_group) ;
486479
487- // Create preview expandable row
488- let preview_expander = adw:: ExpanderRow :: new ( ) ;
489- preview_expander. set_title ( & gettext ( "File Preview" ) ) ;
490- preview_expander. set_subtitle ( & gettext ( "Loading..." ) ) ;
491- preview_expander. set_enable_expansion ( false ) ;
492- preview_expander. set_visible ( false ) ;
480+ // Create preview section with always-visible text view
481+ let preview_label = gtk:: Label :: new ( Some ( & gettext ( "Configuration Preview" ) ) ) ;
482+ preview_label. set_halign ( gtk:: Align :: Start ) ;
483+ preview_label. add_css_class ( "heading" ) ;
493484
494485 // Create TextView for content display
495486 let text_view = gtk:: TextView :: new ( ) ;
496487 text_view. set_editable ( false ) ;
497488 text_view. set_cursor_visible ( false ) ;
498489 text_view. set_monospace ( true ) ;
499490 text_view. set_wrap_mode ( gtk:: WrapMode :: None ) ;
500- text_view. set_margin_start ( 12 ) ;
501- text_view. set_margin_end ( 12 ) ;
502- text_view. set_margin_top ( 6 ) ;
503- text_view. set_margin_bottom ( 6 ) ;
504491
505492 // Wrap TextView in ScrolledWindow
506493 let scrolled_window = gtk:: ScrolledWindow :: new ( ) ;
@@ -509,28 +496,11 @@ impl CreateDistroboxDialog {
509496 scrolled_window. set_max_content_height ( 400 ) ;
510497 scrolled_window. set_vexpand ( true ) ;
511498
512- // Create a box to hold the scrolled window
513- let preview_box = gtk :: Box :: new ( gtk :: Orientation :: Vertical , 0 ) ;
499+ let preview_box = gtk :: Box :: new ( gtk :: Orientation :: Vertical , 6 ) ;
500+ preview_box. append ( & preview_label ) ;
514501 preview_box. append ( & scrolled_window) ;
515- preview_expander. add_row ( & preview_box) ;
516-
517- // Create security warning InfoBar
518- let warning_infobar = adw:: Banner :: new ( & gettext ( "Review the file contents carefully before proceeding. Only create containers from trusted sources." ) ) ;
519- warning_infobar. set_revealed ( false ) ;
520- warning_infobar. set_button_label ( Some ( & gettext ( "Re-download" ) ) ) ;
521-
522- // Create approval checkbox
523- let approval_checkbox = gtk:: CheckButton :: new ( ) ;
524- approval_checkbox. set_label ( Some ( & gettext ( "I have reviewed the file and trust this source" ) ) ) ;
525- approval_checkbox. set_margin_start ( 12 ) ;
526- approval_checkbox. set_margin_end ( 12 ) ;
527- approval_checkbox. set_margin_top ( 6 ) ;
528- approval_checkbox. set_margin_bottom ( 6 ) ;
529- approval_checkbox. set_visible ( false ) ;
530-
531- content. append ( & preview_expander) ;
532- content. append ( & warning_infobar) ;
533- content. append ( & approval_checkbox) ;
502+
503+ content. append ( & preview_box) ;
534504
535505 // Add create button for URL
536506 let create_btn = self . build_create_btn ( ) ;
@@ -559,45 +529,26 @@ impl CreateDistroboxDialog {
559529
560530 // Wire ini_content_query success handler
561531 ini_content_query. connect_success ( clone ! (
562- #[ weak( rename_to=this) ]
563- self ,
564- #[ weak]
565- preview_expander,
566532 #[ weak]
567533 text_view,
568534 #[ weak]
569- warning_infobar,
570- #[ weak]
571- approval_checkbox,
535+ create_btn,
572536 move |content| {
573- // Show preview section
574- preview_expander. set_visible( true ) ;
575- preview_expander. set_enable_expansion( true ) ;
576- preview_expander. set_subtitle( & gettext( "Downloaded successfully" ) ) ;
577- preview_expander. set_expanded( true ) ; // Auto-expand on first successful download
578-
579537 // Set content in TextView
580538 text_view. buffer( ) . set_text( content) ;
581539
582- // Show warning and approval checkbox
583- warning_infobar. set_revealed( true ) ;
584- approval_checkbox. set_visible( true ) ;
585-
586- // Show success toast
587- let toast = adw:: Toast :: new( & gettext( "File downloaded successfully" ) ) ;
588- this. imp( ) . toast_overlay. add_toast( toast) ;
540+ // Enable create button
541+ create_btn. set_sensitive( true ) ;
589542 }
590543 ) ) ;
591544
592545 // Wire ini_content_query loading handler
593546 ini_content_query. connect_loading ( clone ! (
594547 #[ weak]
595- preview_expander ,
548+ create_btn ,
596549 move |is_loading| {
597550 if is_loading {
598- preview_expander. set_visible( true ) ;
599- preview_expander. set_subtitle( & gettext( "Downloading..." ) ) ;
600- preview_expander. set_enable_expansion( false ) ;
551+ create_btn. set_sensitive( false ) ;
601552 }
602553 }
603554 ) ) ;
@@ -607,17 +558,12 @@ impl CreateDistroboxDialog {
607558 #[ weak( rename_to=this) ]
608559 self ,
609560 #[ weak]
610- preview_expander,
611- #[ weak]
612- warning_infobar,
561+ create_btn,
613562 #[ weak]
614- approval_checkbox ,
563+ url_row ,
615564 move |error| {
616- preview_expander. set_visible( true ) ;
617- preview_expander. set_subtitle( & gettext( "Failed to download" ) ) ;
618- preview_expander. set_enable_expansion( false ) ;
619- warning_infobar. set_revealed( false ) ;
620- approval_checkbox. set_visible( false ) ;
565+ create_btn. set_sensitive( false ) ;
566+ url_row. add_css_class( "error" ) ;
621567
622568 let toast = adw:: Toast :: new( & format!( "{}: {}" , gettext( "Download failed" ) , error) ) ;
623569 this. imp( ) . toast_overlay. add_toast( toast) ;
@@ -626,124 +572,24 @@ impl CreateDistroboxDialog {
626572
627573 * self . imp ( ) . ini_content_query . borrow_mut ( ) = Some ( ini_content_query. clone ( ) ) ;
628574
629- // Create URL validation query with debouncing
630- let url_validation_query: Query < bool > = Query :: new (
631- "url-validation" . to_string ( ) ,
632- clone ! (
633- #[ weak( rename_to=this) ]
634- self ,
635- #[ upgrade_or_panic]
636- move || async move {
637- if let Some ( url_text) = this. assemble_url( ) {
638- if url_text. is_empty( ) {
639- return Ok ( false ) ;
640- }
641- this. validate_url( & url_text) . await
642- } else {
643- Ok ( false )
644- }
645- }
646- ) ,
647- ) . with_timeout ( Duration :: from_secs ( 10 ) ) ;
648-
649- url_validation_query. connect_success ( clone ! (
650- #[ weak( rename_to=this) ]
651- self ,
652- #[ weak]
653- url_row,
654- #[ strong]
655- ini_content_query,
656- move |is_valid| {
657- this. set_url_validated( * is_valid) ;
658-
659- if !is_valid {
660- let toast = adw:: Toast :: new( & gettext( "Could not connect to URL" ) ) ;
661- this. imp( ) . toast_overlay. add_toast( toast) ;
662- url_row. add_css_class( "error" ) ;
663- } else {
664- url_row. remove_css_class( "error" ) ;
665- // Trigger download when URL is valid
666- ini_content_query. refetch( ) ;
667- }
668- }
669- ) ) ;
670-
671- url_validation_query. connect_error ( clone ! (
672- #[ weak]
673- url_row,
674- move |_| {
675- url_row. add_css_class( "error" ) ;
676- }
677- ) ) ;
678-
679- * self . imp ( ) . url_validation_query . borrow_mut ( ) = Some ( url_validation_query. clone ( ) ) ;
680-
681575 url_row. connect_changed ( clone ! (
682576 #[ weak( rename_to=this) ]
683577 self ,
684578 #[ weak]
685579 create_btn,
686580 #[ weak]
687- preview_expander,
688- #[ weak]
689- warning_infobar,
690- #[ weak]
691- approval_checkbox,
581+ text_view,
692582 #[ strong]
693- url_validation_query ,
583+ ini_content_query ,
694584 move |entry| {
695585 this. set_assemble_url( Some ( entry. text( ) ) ) ;
696- this. set_url_validated( false ) ;
697- this. set_ini_approved( false ) ;
698586 create_btn. set_sensitive( false ) ;
699- // Clear error CSS when user types
700587 entry. remove_css_class( "error" ) ;
701588
702- // Reset UI state on URL change
703- preview_expander. set_visible( false ) ;
704- warning_infobar. set_revealed( false ) ;
705- approval_checkbox. set_visible( false ) ;
706- approval_checkbox. set_active( false ) ;
589+ text_view. buffer( ) . set_text( "" ) ;
707590
708- // Debounced validation
709- url_validation_query. refetch_with( Query :: debounce( Duration :: from_millis( 500 ) ) ) ;
710- }
711- ) ) ;
712-
713- // Also validate immediately on Apply button press
714- url_row. connect_apply ( clone ! (
715- #[ strong]
716- url_validation_query,
717- move |_| {
718- url_validation_query. refetch_with( Query :: immediate( ) ) ;
719- }
720- ) ) ;
721-
722- // Handle approval checkbox changes
723- approval_checkbox. connect_toggled ( clone ! (
724- #[ weak( rename_to=this) ]
725- self ,
726- #[ weak]
727- create_btn,
728- move |checkbox| {
729- let is_approved = checkbox. is_active( ) ;
730- this. set_ini_approved( is_approved) ;
731- // Update create button sensitivity
732- let is_valid = this. url_validated( ) ;
733- create_btn. set_sensitive( is_valid && is_approved) ;
734- }
735- ) ) ;
736-
737- // Handle re-download button in warning banner
738- warning_infobar. connect_button_clicked ( clone ! (
739- #[ weak]
740- approval_checkbox,
741- #[ strong]
742- ini_content_query,
743- move |_| {
744- // Reset approval when re-downloading
745- approval_checkbox. set_active( false ) ;
746- ini_content_query. refetch( ) ;
591+ // Debounced download (validation happens implicitly)
592+ ini_content_query. refetch_with( Query :: debounce( Duration :: from_millis( 500 ) ) ) ;
747593 }
748594 ) ) ;
749595
@@ -1167,22 +1013,6 @@ impl CreateDistroboxDialog {
11671013 }
11681014 }
11691015
1170- async fn validate_url ( & self , url : & str ) -> anyhow:: Result < bool > {
1171- // Use curl with HEAD request to validate URL
1172- // CRITICAL: Use self.root_store().command_runner() for Flatpak compatibility
1173- let command_runner = self . root_store ( ) . command_runner ( ) ;
1174- let mut cmd = Command :: new ( "curl" ) ;
1175- cmd. arg ( "-s" ) ; // Silent
1176- cmd. arg ( "-f" ) ; // Fail on HTTP errors
1177- cmd. arg ( "-I" ) ; // HEAD request only
1178- cmd. arg ( "--connect-timeout" ) ;
1179- cmd. arg ( "5" ) ; // 5 second connection timeout
1180- cmd. arg ( url) ;
1181-
1182- let output = command_runner. output ( cmd) . await ?;
1183- Ok ( output. status . success ( ) )
1184- }
1185-
11861016 async fn download_ini_file ( & self , url : & str ) -> anyhow:: Result < String > {
11871017 // Download the .ini file content using curl
11881018 // CRITICAL: Use self.root_store().command_runner() for Flatpak compatibility
0 commit comments