|
|
@@ -1,7 +1,7 @@
|
|
|
using System.Collections.Generic;
|
|
|
-using System.Globalization;
|
|
|
using System.Windows;
|
|
|
using System.Windows.Controls;
|
|
|
+using System.Windows.Input;
|
|
|
using System.Windows.Media;
|
|
|
using System.Windows.Media.Animation;
|
|
|
using System.Windows.Threading;
|
|
|
@@ -14,14 +14,11 @@ public partial class MainWindow : Window
|
|
|
{
|
|
|
private readonly NetworkAdapterService _networkAdapterService = new();
|
|
|
private readonly PasswordStoreService _passwordStoreService = new();
|
|
|
- private readonly NetworkConfigurationService _networkConfigurationService = new();
|
|
|
private readonly DiscoveryService _discoveryService = new();
|
|
|
private readonly ServerApiService _serverApiService = new();
|
|
|
- private readonly AdminPrivilegeService _adminPrivilegeService = new();
|
|
|
private IReadOnlyList<AdapterInfo> _adapters = [];
|
|
|
- private bool _isShowingPassword;
|
|
|
+ private IReadOnlyList<DiscoveredDevice> _discoveredDevices = [];
|
|
|
private bool _isBusy;
|
|
|
- private bool _suppressPasswordSync;
|
|
|
private CancellationTokenSource? _statusMessageCts;
|
|
|
|
|
|
public MainWindow()
|
|
|
@@ -30,19 +27,14 @@ public partial class MainWindow : Window
|
|
|
Loaded += MainWindow_OnLoaded;
|
|
|
}
|
|
|
|
|
|
- private async void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
|
|
|
+ private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
|
|
|
{
|
|
|
- await LoadInitialStateAsync();
|
|
|
+ LoadInitialState();
|
|
|
}
|
|
|
|
|
|
- private async Task LoadInitialStateAsync()
|
|
|
+ private void LoadInitialState()
|
|
|
{
|
|
|
- AdminStateTextBlock.Text = _adminPrivilegeService.IsAdministrator()
|
|
|
- ? "管理员状态:当前已以管理员身份运行,可执行本机网卡切换。"
|
|
|
- : "管理员状态:当前不是管理员运行,切换到维护网络会失败。";
|
|
|
-
|
|
|
_adapters = _networkAdapterService.GetEthernetAdapters();
|
|
|
- await _networkAdapterService.ProbeMaintenanceReachabilityAsync(_adapters);
|
|
|
_adapters = _adapters
|
|
|
.OrderByDescending(adapter => adapter.RecommendationScore)
|
|
|
.ThenBy(adapter => adapter.Name)
|
|
|
@@ -51,25 +43,15 @@ public partial class MainWindow : Window
|
|
|
|
|
|
var recommendedAdapter = _networkAdapterService.GetRecommendedAdapter(_adapters);
|
|
|
|
|
|
- var savedPassword = _passwordStoreService.LoadPassword();
|
|
|
- if (!string.IsNullOrWhiteSpace(savedPassword))
|
|
|
- {
|
|
|
- PasswordBox.Password = savedPassword;
|
|
|
- PasswordTextBox.Text = savedPassword;
|
|
|
- }
|
|
|
-
|
|
|
if (recommendedAdapter is not null)
|
|
|
{
|
|
|
AdapterComboBox.SelectedItem = recommendedAdapter;
|
|
|
- UpdateAdapterDetails(recommendedAdapter);
|
|
|
}
|
|
|
else if (_adapters.Count > 0)
|
|
|
{
|
|
|
AdapterComboBox.SelectedIndex = 0;
|
|
|
- UpdateAdapterDetails(_adapters[0]);
|
|
|
}
|
|
|
|
|
|
- AppendLog("客户端已加载连接页。", true);
|
|
|
UpdateButtonStates();
|
|
|
}
|
|
|
|
|
|
@@ -77,153 +59,102 @@ public partial class MainWindow : Window
|
|
|
{
|
|
|
if (AdapterComboBox.SelectedItem is not AdapterInfo adapter)
|
|
|
{
|
|
|
- UpdateAdapterDetails(null);
|
|
|
+ ClearDiscoveredDevices();
|
|
|
SetStatus("请选择一块有线网卡。", false);
|
|
|
UpdateButtonStates();
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- UpdateAdapterDetails(adapter);
|
|
|
if (!adapter.HasLink)
|
|
|
{
|
|
|
+ ClearDiscoveredDevices();
|
|
|
SetStatus("当前网卡未检测到链路,请检查网线连接。", true);
|
|
|
+ UpdateButtonStates();
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
UpdateButtonStates();
|
|
|
+ _ = SearchDevicesAsync(adapter);
|
|
|
}
|
|
|
|
|
|
- private async void SwitchMaintenanceButton_OnClick(object sender, RoutedEventArgs e)
|
|
|
+ private async void RefreshAdaptersButton_OnClick(object sender, RoutedEventArgs e)
|
|
|
{
|
|
|
- if (!_adminPrivilegeService.IsAdministrator())
|
|
|
- {
|
|
|
- SetStatus("当前程序未以管理员身份运行,无法修改本机网卡。", true);
|
|
|
- MessageBox.Show(this, "请以管理员身份运行客户端后再切换到维护网络。", "需要管理员权限", MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (AdapterComboBox.SelectedItem is not AdapterInfo adapter)
|
|
|
- {
|
|
|
- SetStatus("请先选择一块网卡。", true);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- PersistPasswordIfNeeded();
|
|
|
-
|
|
|
- if (adapter.IsReachableToMaintenance)
|
|
|
- {
|
|
|
- SetStatus("当前网卡已经可以直接访问 169.254.100.2,无需切换到维护网络。", true);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
SetBusyState(true);
|
|
|
- SetStatus("正在切换到维护网络,请稍候。", true);
|
|
|
- await Dispatcher.InvokeAsync(() => { }, System.Windows.Threading.DispatcherPriority.Render);
|
|
|
-
|
|
|
try
|
|
|
{
|
|
|
- await _networkConfigurationService.ConfigureMaintenanceNetworkAsync(adapter);
|
|
|
- SetStatus("已切换到维护网络。", true);
|
|
|
- await RefreshAdaptersAsync(adapter.Id);
|
|
|
+ RefreshAdapters();
|
|
|
+ SetStatus("已刷新本机网卡。", true);
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
- SetStatus($"切换维护网络失败:{ex.Message}", true);
|
|
|
- MessageBox.Show(this, ex.Message, "切换维护网络失败", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
|
+ SetStatus($"刷新本机网卡失败:{ex.Message}", true);
|
|
|
+ MessageBox.Show(this, ex.Message, "刷新失败", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
|
}
|
|
|
finally
|
|
|
{
|
|
|
SetBusyState(false);
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- private async void RefreshAdaptersButton_OnClick(object sender, RoutedEventArgs e)
|
|
|
- {
|
|
|
- SetBusyState(true);
|
|
|
- try
|
|
|
+ if (AdapterComboBox.SelectedItem is AdapterInfo adapter)
|
|
|
{
|
|
|
- await RefreshAdaptersAsync();
|
|
|
- SetStatus("已刷新本机网卡和管理口探测结果。", true);
|
|
|
+ await SearchDevicesAsync(adapter);
|
|
|
}
|
|
|
- catch (Exception ex)
|
|
|
+ }
|
|
|
+
|
|
|
+ private async void SearchDevicesButton_OnClick(object sender, RoutedEventArgs e)
|
|
|
+ {
|
|
|
+ if (AdapterComboBox.SelectedItem is AdapterInfo adapter)
|
|
|
{
|
|
|
- SetStatus($"刷新本机网卡失败:{ex.Message}", true);
|
|
|
- MessageBox.Show(this, ex.Message, "刷新失败", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
|
+ await SearchDevicesAsync(adapter);
|
|
|
}
|
|
|
- finally
|
|
|
+ else
|
|
|
{
|
|
|
- SetBusyState(false);
|
|
|
+ SetStatus("请先选择一块网卡。", true);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private async void DiscoverConnectButton_OnClick(object sender, RoutedEventArgs e)
|
|
|
+ private async Task SearchDevicesAsync(AdapterInfo adapter)
|
|
|
{
|
|
|
- if (string.IsNullOrWhiteSpace(GetCurrentPassword()))
|
|
|
+ if (_isBusy)
|
|
|
{
|
|
|
- SetStatus("请输入管理密码。", true);
|
|
|
- MessageBox.Show(this, "请先在右侧“管理密码(必填)”区域输入密码。", "缺少管理密码", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- PersistPasswordIfNeeded();
|
|
|
+ if (string.IsNullOrWhiteSpace(adapter.IPv4Address))
|
|
|
+ {
|
|
|
+ ClearDiscoveredDevices();
|
|
|
+ SetStatus("当前网卡没有可用 IPv4,无法搜索设备。", true);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!adapter.HasLink)
|
|
|
+ {
|
|
|
+ ClearDiscoveredDevices();
|
|
|
+ SetStatus("当前网卡未检测到链路,请检查网线连接。", true);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
SetBusyState(true);
|
|
|
- SetStatus("正在检查当前网卡是否可直接访问管理口。", true);
|
|
|
+ ClearDiscoveredDevices();
|
|
|
+ SetStatus("正在通过当前网卡广播搜索设备。", true);
|
|
|
await Dispatcher.InvokeAsync(() => { }, System.Windows.Threading.DispatcherPriority.Render);
|
|
|
|
|
|
try
|
|
|
{
|
|
|
- if (AdapterComboBox.SelectedItem is AdapterInfo adapter && adapter.IsReachableToMaintenance)
|
|
|
- {
|
|
|
- var directResult = await _serverApiService.CheckHealthAsync("http://169.254.100.2:48888", GetCurrentPassword(), adapter.IPv4Address);
|
|
|
- if (directResult.Success)
|
|
|
- {
|
|
|
- SetStatus("连接成功,无需切换本机网卡。", true);
|
|
|
- OpenDeviceDetailsWindow("http://169.254.100.2:48888", adapter.IPv4Address);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (directResult.StatusCode == 401)
|
|
|
- {
|
|
|
- SetStatus("该网卡可以直连管理口,但管理密码错误。", true);
|
|
|
- MessageBox.Show(this, "当前网卡已经可以直连 Server,但密码校验失败,请确认密码是否正确。", "密码错误", MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (directResult.StatusCode == 403)
|
|
|
- {
|
|
|
- SetStatus("该网卡可以直连管理口,但 Server 拒绝访问,请确认远端是否还是旧版本。", true);
|
|
|
- MessageBox.Show(this, "当前网卡已经可以直连 Server,但请求被拒绝。请确认 Linux 端是否运行的是最新版本 Server。", "访问被拒绝", MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- SetStatus($"该网卡虽可建立连接,但直连 HTTP 校验失败:{directResult.Message}。正在尝试设备发现。", true);
|
|
|
- }
|
|
|
-
|
|
|
- SetStatus("当前网卡无法完成直连校验,正在发现设备,请稍候。", true);
|
|
|
- var selectedAdapter = AdapterComboBox.SelectedItem as AdapterInfo;
|
|
|
- var device = await _discoveryService.DiscoverAsync(selectedAdapter?.IPv4Address ?? string.Empty);
|
|
|
- if (device is null)
|
|
|
+ _discoveredDevices = await _discoveryService.DiscoverManyAsync(adapter.IPv4Address);
|
|
|
+ DiscoveredDevicesListView.ItemsSource = _discoveredDevices;
|
|
|
+ if (_discoveredDevices.Count == 0)
|
|
|
{
|
|
|
- SetStatus("未发现设备。如果当前网卡不可达,请先切换到维护网络。", true);
|
|
|
+ SetStatus("未发现 169.254 开头的设备 IP,请确认网卡、网线、远端服务和维护网段配置。", true);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- SetStatus("已发现设备,正在验证连接。", true);
|
|
|
-
|
|
|
- var discoveredResult = await _serverApiService.CheckHealthAsync($"http://{device.Lan2Ip}:48888", GetCurrentPassword(), selectedAdapter?.IPv4Address ?? string.Empty);
|
|
|
- if (discoveredResult.Success)
|
|
|
- {
|
|
|
- SetStatus("连接成功。", true);
|
|
|
- OpenDeviceDetailsWindow($"http://{device.Lan2Ip}:48888", selectedAdapter?.IPv4Address ?? string.Empty);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- SetStatus($"设备已发现,但 HTTP 验证失败:{discoveredResult.Message}", true);
|
|
|
- }
|
|
|
+ SetStatus($"已发现 {_discoveredDevices.Count} 台设备,请双击 IP 连接。", true);
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
- SetStatus($"连接失败:{ex.Message}", true);
|
|
|
- MessageBox.Show(this, ex.Message, "连接失败", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
|
+ SetStatus($"搜索设备失败:{ex.Message}", true);
|
|
|
+ MessageBox.Show(this, ex.Message, "搜索设备失败", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
|
}
|
|
|
finally
|
|
|
{
|
|
|
@@ -231,34 +162,26 @@ public partial class MainWindow : Window
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private void PersistPasswordIfNeeded()
|
|
|
+ private void SavePasswordForDevice(DiscoveredDevice device, string password)
|
|
|
{
|
|
|
- var password = GetCurrentPassword();
|
|
|
- if (!string.IsNullOrWhiteSpace(password))
|
|
|
+ var deviceKey = GetDevicePasswordKey(device);
|
|
|
+ if (!string.IsNullOrWhiteSpace(deviceKey) && !string.IsNullOrWhiteSpace(password))
|
|
|
{
|
|
|
- _passwordStoreService.SavePassword(password);
|
|
|
- return;
|
|
|
+ _passwordStoreService.SavePassword(deviceKey, password);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private string GetCurrentPassword()
|
|
|
- {
|
|
|
- return _isShowingPassword ? PasswordTextBox.Text : PasswordBox.Password;
|
|
|
- }
|
|
|
-
|
|
|
private void UpdateButtonStates()
|
|
|
{
|
|
|
var adapter = AdapterComboBox.SelectedItem as AdapterInfo;
|
|
|
var hasAdapter = adapter is not null;
|
|
|
RefreshAdaptersButton.IsEnabled = !_isBusy;
|
|
|
- SwitchMaintenanceButton.IsEnabled = !_isBusy && hasAdapter;
|
|
|
- DiscoverConnectButton.IsEnabled = !_isBusy && hasAdapter && adapter!.HasLink;
|
|
|
+ SearchDevicesButton.IsEnabled = !_isBusy && hasAdapter && adapter!.HasLink;
|
|
|
}
|
|
|
|
|
|
- private async Task RefreshAdaptersAsync(string? selectedAdapterId = null)
|
|
|
+ private void RefreshAdapters(string? selectedAdapterId = null)
|
|
|
{
|
|
|
_adapters = _networkAdapterService.GetEthernetAdapters();
|
|
|
- await _networkAdapterService.ProbeMaintenanceReachabilityAsync(_adapters);
|
|
|
_adapters = _adapters
|
|
|
.OrderByDescending(adapter => adapter.RecommendationScore)
|
|
|
.ThenBy(adapter => adapter.Name)
|
|
|
@@ -272,51 +195,139 @@ public partial class MainWindow : Window
|
|
|
if (selected is not null)
|
|
|
{
|
|
|
AdapterComboBox.SelectedItem = selected;
|
|
|
- UpdateAdapterDetails(selected);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private void UpdateAdapterDetails(AdapterInfo? adapter)
|
|
|
+ private void ClearDiscoveredDevices()
|
|
|
+ {
|
|
|
+ _discoveredDevices = [];
|
|
|
+ DiscoveredDevicesListView.ItemsSource = _discoveredDevices;
|
|
|
+ DiscoveryStateTextBlock.Text = "选择网卡后会自动搜索设备。";
|
|
|
+ }
|
|
|
+
|
|
|
+ private async void DiscoveredDevicesListView_OnMouseDoubleClick(object sender, MouseButtonEventArgs e)
|
|
|
+ {
|
|
|
+ if (!_isBusy && DiscoveredDevicesListView.SelectedItem is DiscoveredDevice device)
|
|
|
+ {
|
|
|
+ await ConnectToDeviceAsync(device);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void DiscoveredDevicesListView_OnSizeChanged(object sender, SizeChangedEventArgs e)
|
|
|
{
|
|
|
- if (adapter is null)
|
|
|
+ var availableWidth = DiscoveredDevicesListView.ActualWidth - 36;
|
|
|
+ if (availableWidth <= 0)
|
|
|
{
|
|
|
- AdapterProbeTextBlock.Text = "-";
|
|
|
- ApplyAdapterProbeStyle("未探测");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- AdapterProbeTextBlock.Text = $"{adapter.ProbeStatus} / {adapter.ProbeReason}";
|
|
|
- ApplyAdapterProbeStyle(adapter.ProbeStatus);
|
|
|
+ DeviceIpColumn.Width = Math.Max(130, availableWidth * 0.26);
|
|
|
+ DeviceHostnameColumn.Width = Math.Max(150, availableWidth * 0.30);
|
|
|
+ DeviceMacColumn.Width = Math.Max(180, availableWidth - DeviceIpColumn.Width - DeviceHostnameColumn.Width);
|
|
|
}
|
|
|
|
|
|
- private void ApplyAdapterProbeStyle(string probeStatus)
|
|
|
+ private async Task ConnectToDeviceAsync(DiscoveredDevice device)
|
|
|
{
|
|
|
- var (background, foreground) = probeStatus switch
|
|
|
+ var deviceKey = GetDevicePasswordKey(device);
|
|
|
+ var savedPassword = _passwordStoreService.LoadPassword(deviceKey);
|
|
|
+ var password = string.Empty;
|
|
|
+ if (!string.IsNullOrWhiteSpace(savedPassword))
|
|
|
{
|
|
|
- "可达" => ("#ECFDF5", "#065F46"),
|
|
|
- "未通" or "不可达" => ("#FEF3C7", "#92400E"),
|
|
|
- _ => ("#F3F4F6", "#374151"),
|
|
|
- };
|
|
|
+ password = savedPassword;
|
|
|
+ }
|
|
|
+ else if (!TryPromptForPassword(device, out savedPassword))
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ password = savedPassword;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (string.IsNullOrWhiteSpace(password))
|
|
|
+ {
|
|
|
+ SetStatus("请输入管理密码。", true);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ var selectedAdapter = AdapterComboBox.SelectedItem as AdapterInfo;
|
|
|
+ SetBusyState(true);
|
|
|
+ SetStatus($"正在连接 {device.Lan2Ip}。", true);
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ var baseAddress = $"http://{device.Lan2Ip}:48888";
|
|
|
+ var result = await _serverApiService.CheckHealthAsync(baseAddress, password, selectedAdapter?.IPv4Address ?? string.Empty);
|
|
|
+ if (result.Success)
|
|
|
+ {
|
|
|
+ SavePasswordForDevice(device, password);
|
|
|
+ SetStatus("连接成功。", true);
|
|
|
+ OpenDeviceDetailsWindow(baseAddress, selectedAdapter?.IPv4Address ?? string.Empty, password);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (result.StatusCode == 401)
|
|
|
+ {
|
|
|
+ SetStatus("管理密码错误,请确认密码是否正确。", true);
|
|
|
+ MessageBox.Show(this, "管理密码校验失败,请确认密码是否正确。", "密码错误", MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ SetStatus($"设备已发现,但 HTTP 验证失败:{result.Message}", true);
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ SetStatus($"连接失败:{ex.Message}", true);
|
|
|
+ MessageBox.Show(this, ex.Message, "连接失败", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
|
+ }
|
|
|
+ finally
|
|
|
+ {
|
|
|
+ SetBusyState(false);
|
|
|
+ }
|
|
|
|
|
|
- var backgroundBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString(background));
|
|
|
- var foregroundBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString(foreground));
|
|
|
- AdapterProbeBorder.Background = backgroundBrush;
|
|
|
- AdapterProbeTitleTextBlock.Foreground = foregroundBrush;
|
|
|
- AdapterProbeTextBlock.Foreground = foregroundBrush;
|
|
|
}
|
|
|
|
|
|
- private void OpenDeviceDetailsWindow(string baseAddress, string localIPv4)
|
|
|
+ private void OpenDeviceDetailsWindow(string baseAddress, string localIPv4, string password)
|
|
|
{
|
|
|
- var window = new DeviceDetailsWindow(baseAddress, localIPv4, GetCurrentPassword())
|
|
|
+ var window = new DeviceDetailsWindow(baseAddress, localIPv4, password)
|
|
|
{
|
|
|
Owner = this,
|
|
|
};
|
|
|
window.ShowDialog();
|
|
|
}
|
|
|
|
|
|
+ private bool TryPromptForPassword(DiscoveredDevice device, out string password)
|
|
|
+ {
|
|
|
+ var label = string.IsNullOrWhiteSpace(device.Mac) ? device.Lan2Ip : device.Mac;
|
|
|
+ var window = new PasswordPromptWindow(label)
|
|
|
+ {
|
|
|
+ Owner = this,
|
|
|
+ };
|
|
|
+
|
|
|
+ if (window.ShowDialog() == true)
|
|
|
+ {
|
|
|
+ password = window.Password;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ password = string.Empty;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static string GetDevicePasswordKey(DiscoveredDevice device)
|
|
|
+ {
|
|
|
+ if (!string.IsNullOrWhiteSpace(device.Mac))
|
|
|
+ {
|
|
|
+ return device.Mac;
|
|
|
+ }
|
|
|
+
|
|
|
+ return device.DeviceId;
|
|
|
+ }
|
|
|
+
|
|
|
private void SetStatus(string message, bool addLog)
|
|
|
{
|
|
|
ApplyStatusMessageStyle(message);
|
|
|
+ DiscoveryStateTextBlock.Text = message;
|
|
|
StatusTextBlock.Text = message;
|
|
|
StatusMessageBorder.Opacity = 0;
|
|
|
StatusMessageBorder.Visibility = Visibility.Visible;
|
|
|
@@ -324,10 +335,7 @@ public partial class MainWindow : Window
|
|
|
_statusMessageCts?.Cancel();
|
|
|
_statusMessageCts = new CancellationTokenSource();
|
|
|
_ = HideStatusMessageAsync(_statusMessageCts.Token);
|
|
|
- if (addLog)
|
|
|
- {
|
|
|
- AppendLog(message, false);
|
|
|
- }
|
|
|
+ _ = addLog;
|
|
|
}
|
|
|
|
|
|
private async Task HideStatusMessageAsync(CancellationToken cancellationToken)
|
|
|
@@ -385,70 +393,11 @@ public partial class MainWindow : Window
|
|
|
return markers.Any(marker => message.Contains(marker, StringComparison.Ordinal));
|
|
|
}
|
|
|
|
|
|
- private void AppendLog(string message, bool isInitial)
|
|
|
- {
|
|
|
- var prefix = DateTime.Now.ToString("HH:mm:ss", CultureInfo.InvariantCulture);
|
|
|
- EventLogListBox.Items.Add($"[{prefix}] {message}");
|
|
|
- if (!isInitial)
|
|
|
- {
|
|
|
- EventLogListBox.ScrollIntoView(EventLogListBox.Items[^1]);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
private void SetBusyState(bool isBusy)
|
|
|
{
|
|
|
_isBusy = isBusy;
|
|
|
AdapterComboBox.IsEnabled = !isBusy;
|
|
|
RefreshAdaptersButton.IsEnabled = !isBusy;
|
|
|
- PasswordBox.IsEnabled = !isBusy;
|
|
|
- PasswordTextBox.IsEnabled = !isBusy;
|
|
|
- TogglePasswordVisibilityButton.IsEnabled = !isBusy;
|
|
|
- SwitchMaintenanceButton.IsEnabled = !isBusy && AdapterComboBox.SelectedItem is AdapterInfo;
|
|
|
- DiscoverConnectButton.IsEnabled = !isBusy && AdapterComboBox.SelectedItem is AdapterInfo adapter && adapter.HasLink;
|
|
|
- }
|
|
|
-
|
|
|
- private void TogglePasswordVisibilityButton_OnClick(object sender, RoutedEventArgs e)
|
|
|
- {
|
|
|
- _isShowingPassword = !_isShowingPassword;
|
|
|
- if (_isShowingPassword)
|
|
|
- {
|
|
|
- PasswordTextBox.Text = PasswordBox.Password;
|
|
|
- PasswordBox.Visibility = Visibility.Collapsed;
|
|
|
- PasswordTextBox.Visibility = Visibility.Visible;
|
|
|
- TogglePasswordVisibilityButton.Content = "🙈";
|
|
|
- PasswordTextBox.Focus();
|
|
|
- PasswordTextBox.CaretIndex = PasswordTextBox.Text.Length;
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- PasswordBox.Password = PasswordTextBox.Text;
|
|
|
- PasswordTextBox.Visibility = Visibility.Collapsed;
|
|
|
- PasswordBox.Visibility = Visibility.Visible;
|
|
|
- TogglePasswordVisibilityButton.Content = "👁";
|
|
|
- PasswordBox.Focus();
|
|
|
- }
|
|
|
-
|
|
|
- private void PasswordBox_OnPasswordChanged(object sender, RoutedEventArgs e)
|
|
|
- {
|
|
|
- if (_suppressPasswordSync)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- _suppressPasswordSync = true;
|
|
|
- PasswordTextBox.Text = PasswordBox.Password;
|
|
|
- _suppressPasswordSync = false;
|
|
|
- }
|
|
|
-
|
|
|
- private void PasswordTextBox_OnTextChanged(object sender, TextChangedEventArgs e)
|
|
|
- {
|
|
|
- if (_suppressPasswordSync)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- _suppressPasswordSync = true;
|
|
|
- PasswordBox.Password = PasswordTextBox.Text;
|
|
|
- _suppressPasswordSync = false;
|
|
|
+ SearchDevicesButton.IsEnabled = !isBusy && AdapterComboBox.SelectedItem is AdapterInfo adapter && adapter.HasLink;
|
|
|
}
|
|
|
}
|