diff --git a/Helpers/L.cs b/Helpers/L.cs index 7b3161a..94b6ef5 100644 --- a/Helpers/L.cs +++ b/Helpers/L.cs @@ -42,6 +42,8 @@ public static class L public static string EditServer_Protocol => Loc.GetString("EditServer_Protocol"); public static string EditServer_Encryption => Loc.GetString("EditServer_Encryption"); public static string EditServer_Password => Loc.GetString("EditServer_Password"); + public static string EditServer_ShowPassword => Loc.GetString("EditServer_ShowPassword"); + public static string EditServer_HidePassword => Loc.GetString("EditServer_HidePassword"); public static string EditServer_Transport => Loc.GetString("EditServer_Transport"); public static string EditServer_Path => Loc.GetString("EditServer_Path"); public static string EditServer_WsHost => Loc.GetString("EditServer_WsHost"); diff --git a/Services/DialogService.cs b/Services/DialogService.cs index 256f6cb..a62b060 100644 --- a/Services/DialogService.cs +++ b/Services/DialogService.cs @@ -136,7 +136,7 @@ void SyncDialogButtons() cmbEncryption.Items.Add(existingEnc); cmbEncryption.SelectedItem = existing?.Encryption ?? "aes-128-gcm"; var txtUsername = new TextBox { Header = L.EditServer_SocksUsername, Text = existing?.Username ?? string.Empty }; - var txtPassword = new PasswordBox { Header = L.EditServer_Password, Password = existing?.Password ?? string.Empty }; + var txtPassword = CreateRevealablePasswordBox(L.EditServer_Password, existing?.Password); var txtUuid = new TextBox { Header = "UUID (VMess / VLESS)", Text = existing?.Uuid ?? string.Empty }; var numAlterId = new NumberBox { Header = "AlterId (VMess)", Value = existing?.AlterId ?? 0, Minimum = 0, Maximum = 65535 }; @@ -1288,6 +1288,51 @@ public async Task ShowDnsSettingsDialogAsync(AppSettings settings, bool is private static Border Wrap(FrameworkElement child) => new Border { Child = child }; + + private const string RevealGlyph = "\uE7B3"; // RedEye + private const string ConcealGlyph = "\uED1A"; // Hide + + /// + /// A PasswordBox whose header carries a reveal toggle on the right. + /// + /// PasswordRevealMode is forced to Hidden rather than left at the default Peek: the + /// built-in peek button only shows up once the box has focus and the user has typed + /// a character. An existing server's password is assigned here in code, so peek is + /// dead on arrival and the value can never be read back (issue #124). + /// + /// + private static PasswordBox CreateRevealablePasswordBox(string header, string? value) + { + var box = new PasswordBox { Password = value ?? string.Empty }; + + var icon = new FontIcon { FontSize = 14 }; + var toggle = new Button + { + Content = icon, + Padding = new Thickness(6, 0, 6, 0), + Height = 22, + VerticalAlignment = VerticalAlignment.Center, + }; + if (Application.Current.Resources.TryGetValue("SubtleButtonStyle", out var subtleStyle)) + toggle.Style = (Style)subtleStyle; + + void SetRevealed(bool revealed) + { + box.PasswordRevealMode = revealed ? PasswordRevealMode.Visible : PasswordRevealMode.Hidden; + icon.Glyph = revealed ? ConcealGlyph : RevealGlyph; + + var label = revealed ? L.EditServer_HidePassword : L.EditServer_ShowPassword; + ToolTipService.SetToolTip(toggle, label); + AutomationProperties.SetName(toggle, label); + } + + SetRevealed(false); + toggle.Click += (_, _) => SetRevealed(box.PasswordRevealMode != PasswordRevealMode.Visible); + + box.Header = CreateLabelRow(header, toggle); + return box; + } + /// Multi-line raw-JSON editor box (Finalmask / XHTTP extra). private static TextBox CreateJsonTextBox(string header, string? value) => new() { diff --git a/Strings/en-US/Resources.resw b/Strings/en-US/Resources.resw index 706c359..5181e04 100644 --- a/Strings/en-US/Resources.resw +++ b/Strings/en-US/Resources.resw @@ -428,6 +428,12 @@ Password + + Show password + + + Hide password + Transport Protocol diff --git a/Strings/zh-CN/Resources.resw b/Strings/zh-CN/Resources.resw index 9d0b27d..dc0d77f 100644 --- a/Strings/zh-CN/Resources.resw +++ b/Strings/zh-CN/Resources.resw @@ -428,6 +428,12 @@ 密码 + + 显示密码 + + + 隐藏密码 + 传输协议