@@ -836,17 +836,18 @@ fn form_row(
836836 ui : & mut egui:: Ui ,
837837 label : & str ,
838838 hover : Option < & str > ,
839- widget : impl FnOnce ( & mut egui:: Ui ) ,
839+ widget : impl FnOnce ( & mut egui:: Ui , egui :: Id ) ,
840840) {
841841 ui. horizontal ( |ui| {
842842 let resp = ui. add_sized (
843843 [ 120.0 , 20.0 ] ,
844844 egui:: Label :: new ( egui:: RichText :: new ( label) . color ( egui:: Color32 :: from_gray ( 200 ) ) ) ,
845845 ) ;
846+ let label_id = resp. id ;
846847 if let Some ( h) = hover {
847848 resp. on_hover_text ( h) ;
848849 }
849- widget ( ui) ;
850+ widget ( ui, label_id ) ;
850851 } ) ;
851852}
852853
@@ -935,7 +936,7 @@ impl eframe::App for App {
935936 "apps_script: DPI bypass via Apps Script relay (needs cert).\n \
936937 full: tunnel ALL traffic through Apps Script + tunnel node (no cert needed).\n \
937938 direct: SNI-rewrite tunnel only — no relay (Google edge + any fronting_groups)."
938- ) , |ui| {
939+ ) , |ui, _label_id | {
939940 egui:: ComboBox :: from_id_source ( "mode" )
940941 . selected_text ( match self . form . mode . as_str ( ) {
941942 "direct" | "google_only" => "Direct (no relay)" ,
@@ -988,11 +989,12 @@ impl eframe::App for App {
988989 form_row ( ui, "Deployment IDs" , Some (
989990 "One deployment ID per line. Proxy round-robins between them and sidelines \
990991 any ID that hits its daily quota for 10 minutes before retrying."
991- ) , |ui| {
992+ ) , |ui, label_id | {
992993 ui. add ( egui:: TextEdit :: multiline ( & mut self . form . script_id )
993994 . hint_text ( "one deployment ID per line" )
994995 . desired_width ( f32:: INFINITY )
995- . desired_rows ( 3 ) ) ;
996+ . desired_rows ( 3 ) )
997+ . labelled_by ( label_id) ;
996998 } ) ;
997999
9981000 let id_count = self . form . script_id
@@ -1014,19 +1016,21 @@ impl eframe::App for App {
10141016
10151017 form_row ( ui, "Auth key" , Some (
10161018 "Same value as AUTH_KEY inside your Code.gs."
1017- ) , |ui| {
1019+ ) , |ui, label_id | {
10181020 ui. add ( egui:: TextEdit :: singleline ( & mut self . form . auth_key )
10191021 . password ( !self . form . show_auth_key )
1020- . desired_width ( f32:: INFINITY ) ) ;
1022+ . desired_width ( f32:: INFINITY ) )
1023+ . labelled_by ( label_id) ;
10211024 } ) ;
10221025 } ) ;
10231026 } ) ;
10241027
10251028 // ── Section: Network ──────────────────────────────────────────
10261029 section ( ui, "Network" , |ui| {
1027- form_row ( ui, "Google IP" , None , |ui| {
1030+ form_row ( ui, "Google IP" , None , |ui, label_id | {
10281031 ui. add ( egui:: TextEdit :: singleline ( & mut self . form . google_ip )
1029- . desired_width ( f32:: INFINITY ) ) ;
1032+ . desired_width ( f32:: INFINITY ) )
1033+ . labelled_by ( label_id) ;
10301034 } ) ;
10311035 ui. horizontal ( |ui| {
10321036 ui. add_space ( 120.0 + 8.0 ) ;
@@ -1064,9 +1068,10 @@ impl eframe::App for App {
10641068 }
10651069 } ) ;
10661070
1067- form_row ( ui, "Front domain" , None , |ui| {
1071+ form_row ( ui, "Front domain" , None , |ui, label_id | {
10681072 ui. add ( egui:: TextEdit :: singleline ( & mut self . form . front_domain )
1069- . desired_width ( f32:: INFINITY ) ) ;
1073+ . desired_width ( f32:: INFINITY ) )
1074+ . labelled_by ( label_id) ;
10701075 } ) ;
10711076
10721077 // Network sharing: phones, tablets, other laptops on the
@@ -1102,7 +1107,7 @@ impl eframe::App for App {
11021107 other devices then point their HTTP / SOCKS5 proxy at the \
11031108 LAN IP shown below. Make sure your firewall lets in the proxy \
11041109 port — macOS pops up a Firewall prompt the first time."
1105- ) , |ui| {
1110+ ) , |ui, _label_id | {
11061111 if is_custom_bind {
11071112 // The user manually wrote a specific bind IP —
11081113 // don't let the checkbox stomp on it. Show what
@@ -1168,11 +1173,15 @@ impl eframe::App for App {
11681173 egui:: Label :: new ( egui:: RichText :: new ( "Ports" )
11691174 . color ( egui:: Color32 :: from_gray ( 200 ) ) ) ,
11701175 ) ;
1171- ui. label ( egui:: RichText :: new ( "HTTP" ) . small ( ) ) ;
1172- ui. add ( egui:: TextEdit :: singleline ( & mut self . form . listen_port ) . desired_width ( 70.0 ) ) ;
1176+ let http_label = ui. label ( egui:: RichText :: new ( "HTTP" ) . small ( ) ) ;
1177+ ui. add ( egui:: TextEdit :: singleline ( & mut self . form . listen_port )
1178+ . desired_width ( 70.0 ) )
1179+ . labelled_by ( http_label. id ) ;
11731180 ui. add_space ( 10.0 ) ;
1174- ui. label ( egui:: RichText :: new ( "SOCKS5" ) . small ( ) ) ;
1175- ui. add ( egui:: TextEdit :: singleline ( & mut self . form . socks5_port ) . desired_width ( 70.0 ) ) ;
1181+ let socks_label = ui. label ( egui:: RichText :: new ( "SOCKS5" ) . small ( ) ) ;
1182+ ui. add ( egui:: TextEdit :: singleline ( & mut self . form . socks5_port )
1183+ . desired_width ( 70.0 ) )
1184+ . labelled_by ( socks_label. id ) ;
11761185 } ) ;
11771186 } ) ;
11781187
@@ -1197,23 +1206,24 @@ impl eframe::App for App {
11971206 When set, non-HTTP / raw-TCP traffic (Telegram MTProto, IMAP, SSH, …) \
11981207 is chained through it instead of direct. HTTP/HTTPS still go through \
11991208 the Apps Script relay."
1200- ) , |ui| {
1209+ ) , |ui, label_id | {
12011210 ui. add ( egui:: TextEdit :: singleline ( & mut self . form . upstream_socks5 )
12021211 . hint_text ( "empty = direct; 127.0.0.1:50529 for local xray" )
1203- . desired_width ( f32:: INFINITY ) ) ;
1212+ . desired_width ( f32:: INFINITY ) )
1213+ . labelled_by ( label_id) ;
12041214 } ) ;
12051215
12061216 form_row ( ui, "Parallel dispatch" , Some (
12071217 "Fire N Apps Script IDs in parallel per request and take the first \
12081218 response. 0/1 = off. 2-3 kills long-tail latency at N× quota cost. \
12091219 Only effective with multiple IDs configured."
1210- ) , |ui| {
1220+ ) , |ui, _label_id | {
12111221 ui. add ( egui:: DragValue :: new ( & mut self . form . parallel_relay )
12121222 . speed ( 1 )
12131223 . range ( 0 ..=8 ) ) ;
12141224 } ) ;
12151225
1216- form_row ( ui, "Log level" , None , |ui| {
1226+ form_row ( ui, "Log level" , None , |ui, _label_id | {
12171227 egui:: ComboBox :: from_id_source ( "loglevel" )
12181228 . selected_text ( & self . form . log_level )
12191229 . show_ui ( ui, |ui| {
@@ -1965,11 +1975,19 @@ impl App {
19651975 for ( i, row) in self . form . sni_pool . iter_mut ( ) . enumerate ( ) {
19661976 ui. horizontal ( |ui| {
19671977 ui. checkbox ( & mut row. enabled , "" ) ;
1978+ let sni_label = ui. add_sized (
1979+ [ 0.0 , 0.0 ] ,
1980+ egui:: Label :: new (
1981+ egui:: RichText :: new ( format ! ( "SNI name {}" , i) )
1982+ . color ( egui:: Color32 :: TRANSPARENT ) ,
1983+ ) ,
1984+ ) ;
19681985 ui. add (
19691986 egui:: TextEdit :: singleline ( & mut row. name )
19701987 . desired_width ( NAME_W )
19711988 . font ( egui:: TextStyle :: Monospace ) ,
1972- ) ;
1989+ )
1990+ . labelled_by ( sni_label. id ) ;
19731991 let status_txt = match probe_map. get ( & row. name ) {
19741992 Some ( SniProbeState :: Ok ( ms) ) => {
19751993 egui:: RichText :: new ( format ! ( "ok {} ms" , ms) )
@@ -2024,11 +2042,19 @@ impl App {
20242042
20252043 ui. separator ( ) ;
20262044 ui. horizontal ( |ui| {
2045+ let custom_label = ui. add_sized (
2046+ [ 0.0 , 0.0 ] ,
2047+ egui:: Label :: new (
2048+ egui:: RichText :: new ( "Custom SNI" )
2049+ . color ( egui:: Color32 :: TRANSPARENT ) ,
2050+ ) ,
2051+ ) ;
20272052 ui. add (
20282053 egui:: TextEdit :: singleline ( & mut self . form . sni_custom_input )
20292054 . hint_text ( "add a custom SNI (e.g. translate.google.com)" )
20302055 . desired_width ( 280.0 ) ,
2031- ) ;
2056+ )
2057+ . labelled_by ( custom_label. id ) ;
20322058 let add_clicked = ui. button ( "+ Add" ) . clicked ( ) ;
20332059 if add_clicked {
20342060 let new_name = self . form . sni_custom_input . trim ( ) . to_string ( ) ;
0 commit comments