Replace ConnectDialog with ConnectDialogWindow and move UI to XAML

This commit is contained in:
Stone_Red
2026-07-16 00:35:38 +02:00
parent 05d20c9288
commit 24b9e8ab71
3 changed files with 218 additions and 228 deletions
+2 -228
View File
@@ -634,9 +634,8 @@ public sealed class MainWindowViewModel : ViewModelBase
ClientConfig config = ConfigManager.Load();
SavedServer? prefill = config.SavedServers.FirstOrDefault(s =>
string.Equals(s.Url, serverVm.ServerUrl, StringComparison.OrdinalIgnoreCase));
ConnectDialog dialog = new ConnectDialog(config.SavedServers, prefill);
ConnectDialogResult? result = await dialog.ShowAsync(_mainWindow);
ConnectDialogWindow dialog = new ConnectDialogWindow(config.SavedServers, prefill);
ConnectDialogResult? result = await dialog.ShowDialog<ConnectDialogResult?>(_mainWindow);
if (result is null)
{
return;
@@ -754,228 +753,3 @@ public sealed class MainWindowViewModel : ViewModelBase
}
}
public sealed class ConnectDialogResult
{
public string ServerUrl { get; set; } = string.Empty;
public string Username { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
public bool IsRegister { get; set; }
public bool RememberMe { get; set; }
public bool IsSavedSession { get; set; }
public string? SavedRefreshToken { get; set; }
}
public sealed class ConnectDialog(List<SavedServer> savedServers, SavedServer? prefill = null)
{
private readonly List<SavedServer> _savedServers = savedServers;
private readonly SavedServer? _prefill = prefill;
public async Task<ConnectDialogResult?> ShowAsync(Window owner)
{
Window dialog = new Window
{
Title = "Connect to Server",
Width = 450,
Height = 380,
WindowStartupLocation = WindowStartupLocation.CenterOwner,
CanResize = false,
};
StackPanel stack = new StackPanel { Spacing = 8, Margin = new Avalonia.Thickness(15) };
TextBlock urlLabel = new TextBlock { Text = "Server URL:" };
TextBox urlBox = new TextBox { Watermark = "http://localhost:5000", Text = "http://localhost:5000" };
stack.Children.Add(urlLabel);
stack.Children.Add(urlBox);
TextBlock userLabel = new TextBlock { Text = "Username:" };
TextBox userBox = new TextBox { Watermark = "username" };
stack.Children.Add(userLabel);
stack.Children.Add(userBox);
TextBlock passLabel = new TextBlock { Text = "Password:" };
TextBox passBox = new TextBox { Watermark = "password", PasswordChar = '*' };
stack.Children.Add(passLabel);
stack.Children.Add(passBox);
CheckBox rememberMe = new CheckBox { Content = "Remember me", IsChecked = true };
stack.Children.Add(rememberMe);
StackPanel buttonPanel = new StackPanel { Orientation = Avalonia.Layout.Orientation.Horizontal, HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center, Spacing = 10 };
Button loginBtn = new Button { Content = "Login", Width = 100 };
Button registerBtn = new Button { Content = "Register", Width = 100 };
Button cancelBtn = new Button { Content = "Cancel", Width = 100 };
buttonPanel.Children.Add(loginBtn);
buttonPanel.Children.Add(registerBtn);
buttonPanel.Children.Add(cancelBtn);
stack.Children.Add(buttonPanel);
ListBox? serversList = null;
if (_savedServers.Count > 0)
{
TextBlock sep = new TextBlock { Text = "--- Saved Servers ---", HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center };
stack.Children.Add(sep);
serversList = new ListBox
{
Height = 100,
ItemsSource = _savedServers.Select(s => $"{s.Name} ({s.Url}) - {s.Username ?? "?"}").ToList()
};
stack.Children.Add(serversList);
serversList.SelectionChanged += (_, _) =>
{
int idx = serversList.SelectedIndex;
if (idx >= 0 && idx < _savedServers.Count)
{
SavedServer s = _savedServers[idx];
urlBox.Text = s.Url;
userBox.Text = s.Username ?? "";
rememberMe.IsChecked = s.RememberMe;
if (!string.IsNullOrEmpty(s.RefreshToken))
{
passBox.Text = "";
}
}
};
}
if (_prefill is not null)
{
urlBox.Text = _prefill.Url;
userBox.Text = _prefill.Username ?? "";
int idx = _savedServers.FindIndex(s =>
string.Equals(s.Url, _prefill.Url, StringComparison.OrdinalIgnoreCase));
if (idx >= 0 && idx < _savedServers.Count && serversList is not null)
{
serversList.SelectedIndex = idx;
}
}
dialog.Content = new ScrollViewer { Content = stack };
TaskCompletionSource<ConnectDialogResult?> tcs = new TaskCompletionSource<ConnectDialogResult?>();
ConnectDialogResult? result = null;
loginBtn.Click += async (_, _) =>
{
string url = urlBox.Text?.Trim() ?? "";
string user = userBox.Text?.Trim() ?? "";
string pass = passBox.Text ?? "";
if (string.IsNullOrEmpty(url) || string.IsNullOrEmpty(user))
{
await ShowMessageBox(owner, "Validation", "Server URL and username are required.");
return;
}
// Check for saved session
SavedServer? saved = _savedServers.FirstOrDefault(s =>
string.Equals(s.Url, url, StringComparison.OrdinalIgnoreCase) &&
string.Equals(s.Username, user, StringComparison.OrdinalIgnoreCase) &&
!string.IsNullOrEmpty(s.RefreshToken));
if (string.IsNullOrEmpty(pass) && saved is not null)
{
result = new ConnectDialogResult
{
ServerUrl = url,
Username = user,
IsSavedSession = true,
SavedRefreshToken = saved.RefreshToken,
RememberMe = saved.RememberMe,
};
}
else
{
if (string.IsNullOrEmpty(pass))
{
await ShowMessageBox(owner, "Validation", "Password is required.");
return;
}
result = new ConnectDialogResult
{
ServerUrl = url,
Username = user,
Password = pass,
IsRegister = false,
RememberMe = rememberMe.IsChecked ?? false,
};
}
dialog.Close();
_ = tcs.TrySetResult(result);
};
registerBtn.Click += (_, _) =>
{
string url = urlBox.Text?.Trim() ?? "";
string user = userBox.Text?.Trim() ?? "";
string pass = passBox.Text ?? "";
if (string.IsNullOrEmpty(url) || string.IsNullOrEmpty(user) || string.IsNullOrEmpty(pass))
{
_ = ShowMessageBox(owner, "Validation", "Server URL, username, and password are required.");
return;
}
result = new ConnectDialogResult
{
ServerUrl = url,
Username = user,
Password = pass,
IsRegister = true,
RememberMe = rememberMe.IsChecked ?? false,
};
dialog.Close();
_ = tcs.TrySetResult(result);
};
cancelBtn.Click += (_, _) =>
{
dialog.Close();
_ = tcs.TrySetResult(null);
};
dialog.Closed += (_, _) => tcs.TrySetResult(result);
if (owner is not null)
{
await dialog.ShowDialog(owner);
}
else
{
dialog.Show();
}
return await tcs.Task;
}
private static async Task ShowMessageBox(Window owner, string title, string message)
{
Window msgBox = new Window
{
Title = title,
Width = 350,
Height = 150,
WindowStartupLocation = WindowStartupLocation.CenterOwner,
CanResize = false,
};
StackPanel stack = new StackPanel { Spacing = 10, Margin = new Avalonia.Thickness(15) };
stack.Children.Add(new TextBlock { Text = message, TextWrapping = Avalonia.Media.TextWrapping.Wrap });
Button okBtn = new Button { Content = "OK", HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center };
stack.Children.Add(okBtn);
msgBox.Content = stack;
TaskCompletionSource tcs = new TaskCompletionSource();
okBtn.Click += (_, _) => { msgBox.Close(); _ = tcs.TrySetResult(); };
msgBox.Closed += (_, _) => tcs.TrySetResult();
await msgBox.ShowDialog(owner);
await tcs.Task;
}
}
+46
View File
@@ -0,0 +1,46 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
x:Class="Decho.Views.ConnectDialogWindow"
Title="Connect to Server"
Width="400"
MinWidth="400"
MinHeight="300"
SizeToContent="Height"
WindowStartupLocation="CenterOwner"
CanResize="False"
Icon="/Assets/avalonia-logo.ico">
<Border Padding="15">
<StackPanel Spacing="8">
<TextBlock Text="Server URL:" FontWeight="SemiBold" />
<TextBox x:Name="UrlBox" Watermark="http://localhost:5000" />
<TextBlock Text="Username:" FontWeight="SemiBold" />
<TextBox x:Name="UserBox" Watermark="username" />
<TextBlock Text="Password:" FontWeight="SemiBold" />
<TextBox x:Name="PassBox" Watermark="password" PasswordChar="*" />
<CheckBox x:Name="RememberCheck" Content="Remember me" IsChecked="True" />
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center"
Spacing="10"
Margin="0 4 0 0">
<Button Content="Login" Width="90" Click="OnLoginClick" />
<Button Content="Register" Width="90" Click="OnRegisterClick" />
<Button Content="Cancel" Width="90" Click="OnCancelClick" />
</StackPanel>
<TextBlock x:Name="SavedHeader"
Text="--- Saved Servers ---"
HorizontalAlignment="Center"
IsVisible="False" />
<ListBox x:Name="ServersList"
Height="120"
IsVisible="False" />
</StackPanel>
</Border>
</Window>
@@ -0,0 +1,170 @@
using Avalonia.Controls;
using EchoHub.Client.Config;
using System.Linq;
namespace Decho.Views;
public sealed partial class ConnectDialogWindow : Window
{
private readonly List<SavedServer> _savedServers;
public ConnectDialogWindow()
{
InitializeComponent();
_savedServers = [];
}
public ConnectDialogWindow(List<SavedServer> savedServers, SavedServer? prefill)
{
InitializeComponent();
_savedServers = savedServers;
if (savedServers.Count > 0)
{
SavedHeader.IsVisible = true;
ServersList.IsVisible = true;
ServersList.ItemsSource = savedServers.Select(s =>
$"{s.Name} ({s.Url}) - {s.Username ?? "?"}").ToList();
ServersList.SelectionChanged += (_, _) =>
{
int idx = ServersList.SelectedIndex;
if (idx >= 0 && idx < savedServers.Count)
{
SavedServer s = savedServers[idx];
UrlBox.Text = s.Url;
UserBox.Text = s.Username ?? "";
RememberCheck.IsChecked = s.RememberMe;
if (!string.IsNullOrEmpty(s.RefreshToken))
{
PassBox.Text = "";
}
}
};
}
if (prefill is not null)
{
UrlBox.Text = prefill.Url;
UserBox.Text = prefill.Username ?? "";
int idx = savedServers.FindIndex(s =>
string.Equals(s.Url, prefill.Url, StringComparison.OrdinalIgnoreCase));
if (idx >= 0)
{
ServersList.SelectedIndex = idx;
}
}
}
private async void OnLoginClick(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
{
string url = UrlBox.Text?.Trim() ?? "";
string user = UserBox.Text?.Trim() ?? "";
string pass = PassBox.Text ?? "";
if (string.IsNullOrEmpty(url) || string.IsNullOrEmpty(user))
{
await ShowMessageBox("Validation", "Server URL and username are required.");
return;
}
SavedServer? saved = _savedServers.FirstOrDefault(s =>
string.Equals(s.Url, url, StringComparison.OrdinalIgnoreCase) &&
string.Equals(s.Username, user, StringComparison.OrdinalIgnoreCase) &&
!string.IsNullOrEmpty(s.RefreshToken));
if (string.IsNullOrEmpty(pass) && saved is not null)
{
Close(new ConnectDialogResult
{
ServerUrl = url,
Username = user,
IsSavedSession = true,
SavedRefreshToken = saved.RefreshToken,
RememberMe = saved.RememberMe,
});
}
else
{
if (string.IsNullOrEmpty(pass))
{
await ShowMessageBox("Validation", "Password is required.");
return;
}
Close(new ConnectDialogResult
{
ServerUrl = url,
Username = user,
Password = pass,
IsRegister = false,
RememberMe = RememberCheck.IsChecked ?? false,
});
}
}
private void OnRegisterClick(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
{
string url = UrlBox.Text?.Trim() ?? "";
string user = UserBox.Text?.Trim() ?? "";
string pass = PassBox.Text ?? "";
if (string.IsNullOrEmpty(url) || string.IsNullOrEmpty(user) || string.IsNullOrEmpty(pass))
{
_ = ShowMessageBox("Validation", "Server URL, username, and password are required.");
return;
}
Close(new ConnectDialogResult
{
ServerUrl = url,
Username = user,
Password = pass,
IsRegister = true,
RememberMe = RememberCheck.IsChecked ?? false,
});
}
private void OnCancelClick(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
{
Close(null);
}
private async Task ShowMessageBox(string title, string message)
{
Window msgBox = new Window
{
Title = title,
Width = 350,
Height = 150,
WindowStartupLocation = WindowStartupLocation.CenterOwner,
CanResize = false,
};
StackPanel stack = new StackPanel { Spacing = 10, Margin = new Avalonia.Thickness(15) };
stack.Children.Add(new TextBlock { Text = message, TextWrapping = Avalonia.Media.TextWrapping.Wrap });
Button okBtn = new Button { Content = "OK", HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center };
stack.Children.Add(okBtn);
msgBox.Content = stack;
TaskCompletionSource tcs = new TaskCompletionSource();
okBtn.Click += (_, _) => { msgBox.Close(); _ = tcs.TrySetResult(); };
msgBox.Closed += (_, _) => tcs.TrySetResult();
await msgBox.ShowDialog(this);
await tcs.Task;
}
}
public sealed class ConnectDialogResult
{
public string ServerUrl { get; set; } = string.Empty;
public string Username { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
public bool IsRegister { get; set; }
public bool RememberMe { get; set; }
public bool IsSavedSession { get; set; }
public string? SavedRefreshToken { get; set; }
}