@@ -463,7 +463,9 @@ private void ApplyGlanceChips(ConnectionPagePlan plan, bool show)
463463 // — without this the fingerprint can be identical when daily list
464464 // appears/empties at $0.00, leaving a stale chip state.
465465 int dailyCount = cost ? . Daily ? . Count ?? 0 ;
466- var fp = $ "{ topology } |{ hostname } |{ presence } |{ channelOk } /{ channelTotal } |{ dailyCount } |${ todayAmount : 0.00} ";
466+ var sharedToken = activeRec ? . SharedGatewayToken ;
467+ var hasSharedToken = ! string . IsNullOrEmpty ( sharedToken ) ;
468+ var fp = $ "{ topology } |{ hostname } |{ presence } |{ channelOk } /{ channelTotal } |{ dailyCount } |${ todayAmount : 0.00} |st={ sharedToken ? . Length ?? 0 } ";
467469 if ( _glanceChipsFingerprint == fp ) return ;
468470 _glanceChipsFingerprint = fp ;
469471
@@ -509,6 +511,18 @@ private void ApplyGlanceChips(ConnectionPagePlan plan, bool show)
509511 chips . Add ( BuildGlanceChip ( Helpers . FluentIconCatalog . Money , label , neutral : true ) ) ;
510512 }
511513
514+ // 6. Shared token — click to copy.
515+ if ( hasSharedToken )
516+ {
517+ var chip = BuildGlanceChip ( Helpers . FluentIconCatalog . Lock , "Shared token" , neutral : true ) ;
518+ ToolTipService . SetToolTip ( chip , "Tap to copy shared token" ) ;
519+ chip . Tapped += ( _ , _ ) =>
520+ {
521+ ClipboardHelper . CopyText ( sharedToken ! ) ;
522+ } ;
523+ chips . Add ( chip ) ;
524+ }
525+
512526 GlanceChipsHost . ItemsSource = chips ;
513527 }
514528
@@ -1330,6 +1344,11 @@ private void OnEnterAddGateway(object sender, RoutedEventArgs e)
13301344 _editingGatewayId = null ;
13311345 _userIntent = UserIntent . AddingGateway ;
13321346 // Direct is default — make sure the selector is on Direct.
1347+ // Pre-fill the most common local gateway URL.
1348+ DirectUrlBox . Text = "ws://127.0.0.1:18789" ;
1349+ DirectTokenBox . Text = "" ;
1350+ DirectNameBox . Text = "" ;
1351+ AutoFillTokenForUrl ( DirectUrlBox . Text ) ;
13331352 ShowAddPane ( "direct" ) ;
13341353 AddDirectItem . IsSelected = true ;
13351354 RefreshFromSnapshot ( _lastSnapshot ) ;
@@ -1502,7 +1521,7 @@ private void OnEditTunnelSettings(object sender, RoutedEventArgs e)
15021521 _editingGatewayId = rec . Id ;
15031522 _userIntent = UserIntent . AddingGateway ;
15041523 DirectUrlBox . Text = rec . Url ;
1505- DirectTokenBox . Password = rec . SharedGatewayToken ?? "" ;
1524+ DirectTokenBox . Text = rec . SharedGatewayToken ?? "" ;
15061525 DirectNameBox . Text = rec . FriendlyName ?? "" ;
15071526 if ( rec . SshTunnel != null )
15081527 {
@@ -1597,7 +1616,7 @@ private void OnSavedRowEdit(object sender, RoutedEventArgs e)
15971616 _editingGatewayId = gwId ;
15981617 _userIntent = UserIntent . AddingGateway ;
15991618 DirectUrlBox . Text = rec . Url ;
1600- DirectTokenBox . Password = rec . SharedGatewayToken ?? "" ;
1619+ DirectTokenBox . Text = rec . SharedGatewayToken ?? "" ;
16011620 DirectNameBox . Text = rec . FriendlyName ?? "" ;
16021621 if ( rec . SshTunnel != null )
16031622 {
@@ -1653,7 +1672,29 @@ private async void OnSavedRowRemove(object sender, RoutedEventArgs e)
16531672
16541673 private void OnDirectInputChanged ( object sender , RoutedEventArgs e )
16551674 {
1656- ScheduleConnectivityTest ( DirectUrlBox . Text ? . Trim ( ) ) ;
1675+ var url = DirectUrlBox . Text ? . Trim ( ) ;
1676+ ScheduleConnectivityTest ( url ) ;
1677+ AutoFillTokenForUrl ( url ) ;
1678+ }
1679+
1680+ private void OnDirectUrlLostFocus ( object sender , RoutedEventArgs e )
1681+ {
1682+ var url = DirectUrlBox . Text ? . Trim ( ) ;
1683+ ScheduleConnectivityTest ( url ) ;
1684+ // On focus-out, overwrite token even if already populated (user finished editing URL).
1685+ AutoFillTokenForUrl ( url , force : true ) ;
1686+ }
1687+
1688+ private void AutoFillTokenForUrl ( string ? url , bool force = false )
1689+ {
1690+ if ( string . IsNullOrWhiteSpace ( url ) || ( ! force && ! string . IsNullOrEmpty ( DirectTokenBox . Text ) ) )
1691+ return ;
1692+ var match = _gatewayRegistry ? . GetAll ( ) . FirstOrDefault ( g =>
1693+ string . Equals ( g . Url ? . TrimEnd ( '/' ) , url ! . TrimEnd ( '/' ) , StringComparison . OrdinalIgnoreCase ) ) ;
1694+ if ( ! string . IsNullOrEmpty ( match ? . SharedGatewayToken ) )
1695+ DirectTokenBox . Text = match ! . SharedGatewayToken ;
1696+ else if ( force )
1697+ DirectTokenBox . Text = "" ;
16571698 }
16581699
16591700 private void ScheduleConnectivityTest ( string ? rawUrl )
@@ -1762,7 +1803,7 @@ private async Task DoDirectConnectFromAddFormAsync()
17621803 if ( _connectionManager == null || _gatewayRegistry == null ) return ;
17631804
17641805 var url = DirectUrlBox . Text ? . Trim ( ) ;
1765- var token = DirectTokenBox . Password ? . Trim ( ) ;
1806+ var token = DirectTokenBox . Text ? . Trim ( ) ;
17661807 var friendly = DirectNameBox . Text ? . Trim ( ) ;
17671808 if ( string . IsNullOrWhiteSpace ( url ) )
17681809 {
@@ -2282,7 +2323,7 @@ private void OnAddDiscoveredGateway(object sender, RoutedEventArgs e)
22822323 // the token there and clicks Save & connect.
22832324 _editingGatewayId = null ;
22842325 DirectUrlBox . Text = url ;
2285- DirectTokenBox . Password = "" ;
2326+ DirectTokenBox . Text = "" ;
22862327 DirectNameBox . Text = "" ;
22872328 AddDirectItem . IsSelected = true ;
22882329 ShowAddPane ( "direct" ) ;
0 commit comments