@@ -32,6 +32,8 @@ pub struct App {
32
32
config_url : String ,
33
33
repaint_delay : std:: time:: Duration ,
34
34
token_path : String ,
35
+ // confirmation dialog state
36
+ network_to_remove : Option < String > ,
35
37
}
36
38
37
39
impl App {
@@ -56,6 +58,7 @@ impl App {
56
58
config_url : String :: new ( ) ,
57
59
repaint_delay : std:: time:: Duration :: MAX ,
58
60
token_path,
61
+ network_to_remove : None ,
59
62
}
60
63
}
61
64
@@ -270,7 +273,7 @@ impl App {
270
273
// remove action
271
274
let item = MenuItem :: with_id (
272
275
format ! ( "remove_network {config_url_str}" ) ,
273
- "Remove" ,
276
+ "Remove… " ,
274
277
true ,
275
278
None ,
276
279
) ;
@@ -529,6 +532,7 @@ impl ApplicationHandler<UserEvent> for App {
529
532
WindowEvent :: CloseRequested => {
530
533
trace ! ( "Window close requested" ) ;
531
534
self . config_url . clear ( ) ;
535
+ self . network_to_remove = None ;
532
536
self . gl_window . take ( ) ;
533
537
self . gl . take ( ) ;
534
538
self . egui_glow . take ( ) ;
@@ -540,71 +544,155 @@ impl ApplicationHandler<UserEvent> for App {
540
544
self . gl_window . as_mut ( ) . unwrap ( ) . window ( ) ,
541
545
|egui_ctx| {
542
546
egui:: CentralPanel :: default ( ) . show ( egui_ctx, |ui| {
543
- // Helper function to add network
544
- let add_network = |url : String | {
545
- if Url :: parse ( url. trim ( ) ) . is_ok ( ) {
546
- // send event for processing
547
- self . proxy
548
- . send_event ( UserEvent :: AddNetwork ( url) )
549
- . expect ( "Failed to send event" ) ;
550
- true // return true to indicate success
547
+ if let Some ( network_url) = & self . network_to_remove {
548
+ // Confirmation dialog for removing network
549
+ // Get network name/URL for display
550
+ let display_text = if let Some ( Ok ( status) ) =
551
+ self . status . lock ( ) . expect ( "Mutex poisoned" ) . as_ref ( )
552
+ {
553
+ if let Ok ( url) = Url :: parse ( network_url) {
554
+ if let Some ( network) = status. networks . get ( & url) {
555
+ match network. name . as_ref ( ) {
556
+ Some ( name) => Self :: sanitize_menu_text ( name) ,
557
+ None => mask_url ( & url) ,
558
+ }
559
+ } else {
560
+ network_url. clone ( )
561
+ }
562
+ } else {
563
+ network_url. clone ( )
564
+ }
551
565
} else {
552
- false
553
- }
554
- } ;
555
-
556
- // URL input field
557
- ui. label ( "Network configuration URL (https:// or file://):" ) ;
558
- let response = ui. add_sized (
559
- [ ui. available_width ( ) * 1.0 , 0.0 ] ,
560
- egui:: TextEdit :: singleline ( & mut self . config_url )
561
- . hint_text ( "https://example.com/network-config.toml" ) ,
562
- ) ;
563
- // automatically set focus on the text field
564
- response. request_focus ( ) ;
565
-
566
- // Check for Enter key press
567
- let input = ui. input ( |i| i. clone ( ) ) ;
568
- if input. key_pressed ( egui:: Key :: Enter ) {
569
- let url = self . config_url . clone ( ) ;
570
- if add_network ( url) {
566
+ network_url. clone ( )
567
+ } ;
568
+
569
+ ui. vertical_centered ( |ui| {
570
+ ui. label ( format ! (
571
+ "Are you sure you want to remove the network »{}«?" ,
572
+ display_text
573
+ ) ) ;
574
+ } ) ;
575
+ ui. add_space ( 10.0 ) ;
576
+
577
+ // Check for Escape key press
578
+ let input = ui. input ( |i| i. clone ( ) ) ;
579
+ if input. key_pressed ( egui:: Key :: Escape ) {
580
+ trace ! ( "Cancel remove action triggered" ) ;
571
581
cancel = true ;
572
582
}
573
- }
574
-
575
- // Check for Escape key press
576
- if input. key_pressed ( egui:: Key :: Escape ) {
577
- trace ! ( "Cancel action triggered" ) ;
578
- cancel = true ;
579
- }
580
583
581
- ui. add_space ( 5.0 ) ;
582
-
583
- // buttons
584
- ui. horizontal ( |ui| {
585
- ui. with_layout (
586
- egui:: Layout :: right_to_left ( egui:: Align :: Center ) ,
587
- |ui| {
588
- if ui. button ( "Add" ) . clicked ( ) {
589
- let url = self . config_url . clone ( ) ;
590
- if add_network ( url) {
584
+ // buttons - centered
585
+ ui. horizontal ( |ui| {
586
+ ui. with_layout (
587
+ egui:: Layout :: right_to_left ( egui:: Align :: Center ) ,
588
+ |ui| {
589
+ // Add flexible space to center the buttons
590
+ ui. allocate_space ( egui:: Vec2 :: new (
591
+ ui. available_width ( ) * 0.5 - 60.0 ,
592
+ 0.0 ,
593
+ ) ) ;
594
+
595
+ if ui. button ( "Remove" ) . clicked ( ) {
596
+ let url = network_url. clone ( ) ;
597
+ trace ! (
598
+ "Confirmed removing network with URL: {}" ,
599
+ url
600
+ ) ;
601
+
602
+ self . rt . block_on ( async {
603
+ let client =
604
+ RestApiClient :: new ( self . token_path . clone ( ) ) ;
605
+ match client. remove_network ( & url) . await {
606
+ Ok ( _) => {
607
+ trace ! ( "Removed network: {url}" ) ;
608
+ }
609
+ Err ( e) => {
610
+ trace ! (
611
+ "Failed to remove network: {}" ,
612
+ e
613
+ ) ;
614
+ }
615
+ }
616
+ } ) ;
591
617
cancel = true ;
592
618
}
593
- }
594
619
595
- if ui. button ( "Cancel" ) . clicked ( ) {
596
- trace ! ( "Cancel action triggered" ) ;
597
- cancel = true ;
598
- }
599
- } ,
620
+ if ui. button ( "Cancel" ) . clicked ( ) {
621
+ trace ! ( "Cancel remove action triggered" ) ;
622
+ cancel = true ;
623
+ }
624
+ } ,
625
+ ) ;
626
+ } ) ;
627
+ } else {
628
+ // Add network dialog
629
+ // Helper function to add network
630
+ let add_network = |url : String | {
631
+ if Url :: parse ( url. trim ( ) ) . is_ok ( ) {
632
+ // send event for processing
633
+ self . proxy
634
+ . send_event ( UserEvent :: AddNetwork ( url) )
635
+ . expect ( "Failed to send event" ) ;
636
+ true // return true to indicate success
637
+ } else {
638
+ false
639
+ }
640
+ } ;
641
+
642
+ // URL input field
643
+ ui. label ( "Network configuration URL (https:// or file://):" ) ;
644
+ let response = ui. add_sized (
645
+ [ ui. available_width ( ) * 1.0 , 0.0 ] ,
646
+ egui:: TextEdit :: singleline ( & mut self . config_url )
647
+ . hint_text ( "https://example.com/network-config.toml" ) ,
600
648
) ;
601
- } ) ;
649
+ // automatically set focus on the text field
650
+ response. request_focus ( ) ;
651
+
652
+ // Check for Enter key press
653
+ let input = ui. input ( |i| i. clone ( ) ) ;
654
+ if input. key_pressed ( egui:: Key :: Enter ) {
655
+ let url = self . config_url . clone ( ) ;
656
+ if add_network ( url) {
657
+ cancel = true ;
658
+ }
659
+ }
660
+
661
+ // Check for Escape key press
662
+ if input. key_pressed ( egui:: Key :: Escape ) {
663
+ trace ! ( "Cancel action triggered" ) ;
664
+ cancel = true ;
665
+ }
666
+
667
+ ui. add_space ( 10.0 ) ;
668
+
669
+ // buttons
670
+ ui. horizontal ( |ui| {
671
+ ui. with_layout (
672
+ egui:: Layout :: right_to_left ( egui:: Align :: Center ) ,
673
+ |ui| {
674
+ if ui. button ( "Add" ) . clicked ( ) {
675
+ let url = self . config_url . clone ( ) ;
676
+ if add_network ( url) {
677
+ cancel = true ;
678
+ }
679
+ }
680
+
681
+ if ui. button ( "Cancel" ) . clicked ( ) {
682
+ trace ! ( "Cancel action triggered" ) ;
683
+ cancel = true ;
684
+ }
685
+ } ,
686
+ ) ;
687
+ } ) ;
688
+ }
602
689
} ) ;
603
690
} ,
604
691
) ;
605
692
606
693
if cancel {
607
694
self . config_url . clear ( ) ;
695
+ self . network_to_remove = None ;
608
696
self . gl_window . take ( ) ;
609
697
self . gl . take ( ) ;
610
698
self . egui_glow . take ( ) ;
@@ -713,11 +801,23 @@ impl ApplicationHandler<UserEvent> for App {
713
801
id if id == MenuId :: new ( "add_network" ) => {
714
802
trace ! ( "Add network item clicked" ) ;
715
803
804
+ // Close all existing windows/dialogs first
805
+ self . config_url . clear ( ) ;
806
+ self . network_to_remove = None ;
807
+ self . gl_window . take ( ) ;
808
+ self . gl . take ( ) ;
809
+ self . egui_glow . take ( ) ;
810
+
716
811
// create window if it doesn't exist yet
717
812
if let Some ( gl_window) = self . gl_window . as_mut ( ) {
718
813
gl_window. window ( ) . focus_window ( ) ;
719
814
} else {
720
- let ( gl_window, gl) = crate :: glow_tools:: create_display ( event_loop) ;
815
+ let ( gl_window, gl) = crate :: glow_tools:: create_display (
816
+ event_loop,
817
+ "Add Network" ,
818
+ 500.0 ,
819
+ 100.0 ,
820
+ ) ;
721
821
let gl = Arc :: new ( gl) ;
722
822
gl_window. window ( ) . set_visible ( true ) ;
723
823
gl_window. window ( ) . focus_window ( ) ;
@@ -750,19 +850,48 @@ impl ApplicationHandler<UserEvent> for App {
750
850
id if id. 0 . starts_with ( "remove_network " ) => {
751
851
let url = id. 0 . split_once ( ' ' ) . unwrap ( ) . 1 ;
752
852
753
- trace ! ( "Removing network with URL: {}" , url) ;
853
+ trace ! ( "Remove network confirmation dialog for URL: {}" , url) ;
754
854
755
- self . rt . block_on ( async {
756
- let client = RestApiClient :: new ( self . token_path . clone ( ) ) ;
757
- match client. remove_network ( url) . await {
758
- Ok ( _) => {
759
- trace ! ( "Removed network: {url}" ) ;
760
- }
761
- Err ( e) => {
762
- trace ! ( "Failed to remove network: {}" , e) ;
763
- }
764
- }
765
- } ) ;
855
+ // Close all existing windows/dialogs first
856
+ self . config_url . clear ( ) ;
857
+ self . network_to_remove = None ;
858
+ self . gl_window . take ( ) ;
859
+ self . gl . take ( ) ;
860
+ self . egui_glow . take ( ) ;
861
+
862
+ // Store the network URL to be removed and show confirmation dialog
863
+ self . network_to_remove = Some ( url. to_string ( ) ) ;
864
+
865
+ // Create window if it doesn't exist yet
866
+ if let Some ( gl_window) = self . gl_window . as_mut ( ) {
867
+ gl_window. window ( ) . focus_window ( ) ;
868
+ } else {
869
+ let ( gl_window, gl) = crate :: glow_tools:: create_display (
870
+ event_loop,
871
+ "Remove Network" ,
872
+ 400.0 ,
873
+ 80.0 ,
874
+ ) ;
875
+ let gl = Arc :: new ( gl) ;
876
+ gl_window. window ( ) . set_visible ( true ) ;
877
+ gl_window. window ( ) . focus_window ( ) ;
878
+
879
+ let egui_glow =
880
+ egui_glow:: EguiGlow :: new ( event_loop, gl. clone ( ) , None , None , true ) ;
881
+
882
+ let event_loop_proxy = egui:: mutex:: Mutex :: new ( self . proxy . clone ( ) ) ;
883
+ egui_glow
884
+ . egui_ctx
885
+ . set_request_repaint_callback ( move |info| {
886
+ event_loop_proxy
887
+ . lock ( )
888
+ . send_event ( UserEvent :: Redraw ( info. delay ) )
889
+ . expect ( "Cannot send event" ) ;
890
+ } ) ;
891
+ self . gl_window = Some ( gl_window) ;
892
+ self . gl = Some ( gl) ;
893
+ self . egui_glow = Some ( egui_glow) ;
894
+ }
766
895
}
767
896
id if id. 0 . starts_with ( "network_enabled " ) => {
768
897
let url = id. 0 . split_once ( ' ' ) . unwrap ( ) . 1 ;
0 commit comments